为什么在使用for-in控制块时,javascript对象上的内置属性没有迭代,而用户定义的属性是?
例如:
var y = 'car';
for (var j in y)
{
console.log(j);
}
将打印:
0
1
2
即使 String.prototype 具有长度、替换、子字符串等属性。
但是,如果扩展原型,则会迭代任何新属性:
String.prototype.foo = 7;
var y = 'car';
for (var j in y)
{
console.log(j);
}
将打印:
0
1
2
foo
基本上,内置属性在内部标记为"不可枚举"。这意味着,自然不会枚举它们。
编辑:正如Andy善意指出的那样,您可以使用defineProperty
在当前版本的JavaScript中设置enumerable : false
。但是,这似乎根本不支持 Opera ;IE 8 只在 DOM 对象上支持它,而 Safari 只在非 DOM 对象上支持它(在 MDN 上定义属性(查看文件底部以获得浏览器支持))。
所有这些跨浏览器的乐趣意味着,如果您需要一致的浏览器支持,您可能不应该依赖此行为。
下面介绍如何定义不可枚举的属性:
Object.defineProperty(String.prototype, "foo", {value : 7, enumerable : false});
您实际上不需要包含enumerable : false
- 默认情况下,在调用defineProperty
时会false
它。
有一个 propertyIsEnumerable 方法,它返回一个布尔值,指示是否设置了内部 ECMAScript DontEnum 属性(还要注意实现之间的可怕分歧)。如上所述,您不能设置DontEnum
,而只能通过propertyIsEnumerable
查询。
in
var y = 'car';
for (var j in y) {
console.log(j);
}
您正在循环访问 String 实例的属性,该实例被视为字符数组。在这种情况下,数组有 3 个元素,所以它的"属性"是 0,1,2。如果你console.logged
y[j]
,你应该已经看到了'c','a','r'
。
现在,如果你想查看原型属性/方法,你应该查询y的constructor
原型的原型(这是String
):
for (var j in y.constructor.prototype)
{
console.log(j);
}
在
String.prototype.foo = 7;
var y = 'car';
for (var j in y) {
console.log(j);
}
您添加了属性foo
String.prototype
。将属性添加到构造函数 (String) 原型可使其可用于所有实例。字符串文字y
是String
的一个实例,因此你会看到foo
出现在y
中,当枚举它的属性时。
另请参阅:这个SO问题
要扩展其他人的答案,您可以使用Object.defineProperty
将自己的属性标记为不可枚举
var o = {},
def = Object.defineProperty;
def(o, "myProperty", {
"value": 42,
"enumerable": false,
"writeable": true,
"configurable": true
});
请注意,这些属性默认为 false,因此您可以不包含 "enumerable"
以将其设置为 false。