在 ECMAScript 中,原生对象的 prototype 中的预置 property 是不会被遍历出来的,因为这些 property 的 [[Enumerable]] 属性都为 'false'。
关于 Property Attributes 请参考 ECMAScript 规范8.6.1 Property Attributes 中的内容。
关于 for...in 语法的说明请参考 ECMAScript 规范12.6.4 The for-in Statement 中的内容。
关于 Function Prototype Object 的说明请参考 ECMAScript 规范15.3.4 Properties of the Function Prototype Object 中的内容。
改变 Date、Array 或 String 等对象的原型对象中的属性或方法的引用后,再用 for in 遍历一个 Date、Array 或 String 对象时,在 Safari Chrome 中可以遍历出这个修改过的属性或方法名。
代码执行在各浏览器下效果可能不一致。
Chrome Safari |
---|
分析以下代码:
Array.prototype.pop=function(){}; var a=[]; for(var i in a)document.write(i," ");
各浏览器表现如下:
IE Firefox Oprea | Chrome Safari | |
---|---|---|
Array.prototype | 无内容 | pop |
本例中,Array.prototype.pop 被重指向为一个新的函数,在这种情况下,仅在 Chrome Safari 中,'pop' 也将被遍历出来。
将 Array 替换为 Date String 对象后,分别修改它们的属性或方法名,这个修改过的属性或方法名也将被遍历出来。此外,如果覆盖 Math 对象的内置方法,也同样会被遍历,具体可看测试用例:
String.prototype.charCodeAt = function(){}; var s = ''; document.writeln('<p style="background:#CCC" >for in String :</p>'); for(var i in s) document.write(i, ' '); Date.prototype.getFullYear = function(){}; var d = new Date(); document.writeln('<p style="background:#CCC" >for in Date :</p>'); for(var i in d) document.write(i, ' ');
各浏览器表现如下:
IE Firefox Oprea | Chrome Safari | |
---|---|---|
Date.prototype | 无内容 | getFullYear |
String.prototype | 无内容 | charCodeAt |
Math | 无内容 | abs |
但是,如果覆盖 Object Number 对象原型中的 toString valueOf 内置方法则不会被遍历,如下例:
Number.prototype.valueOf = function(){} Number.prototype.toString = function(){} var n = new Number(1); document.writeln('<p style="background:#CCC" >for in Number :</p>'); for(var i in n) document.write(i, ' '); Object.prototype.valueOf = function(){}; Object.prototype.toString = function(){}; var o = new Object(); document.writeln('<p style="background:#CCC" >for in Object :</p>'); for(var i in o) document.write(i, ' ');
各浏览器表现如下:
所有浏览器 | |
---|---|
Number.prototype.toString | 不可被遍历 |
Number.prototype.valueOf | 不可被遍历 |
Object.prototype.toString | 不可被遍历 |
Object.prototype.valueOf | 不可被遍历 |
此外还有特殊情况存在,如下:
document.writeln('<p style="background:#CCC" >for in Function :</p>'); document.writeln('Function.prototype.valueOf is:', Function.prototype.valueOf ? true : false); Function.prototype.valueOf = function() {}; Function.prototype.toString = function() {}; var f = function(){}; for(var i in f) document.write(i, ' ');
各浏览器表现如下:
IE6 IE7 IE8 | Chrome Safari Firefox IE9 Beta | Oprea | |
---|---|---|---|
Function.prototype.valueOf | true | true | true |
Function.prototype1 | 无内容输出 | valueOf | prototype valueOf |
【注】:Function.prototype 并不是一个 javaScript 中指的 object。ECMAScript 中规定了 Function.prototype 需要存在 [[Call]] 内部方法,并且需要实现 call 和 apply 两种 JavaScript 方法。因此,从 JavaScript 语言层面来看, Function.prototype 实质上是个 function 而非 object。
根据 ECMAScript 5th 以及 ECMAScript 3th 中描述,Function.prototype 内没有规定实现 valueOf 方法。但是测试结果证明,所有浏览器都实现了他。但由于这种实现为非标准的,Chrome Safari Firefox Opera IE9 Beta 都没有强制保护这个 valueOf 方法不被枚举。valueOf 原生方法中自带 [[Enumerable]] 属性与原始设定值,由于覆盖这个方法的的新函数并不具备内置的 [[Enumerable]] 属性,导致他可被遍历。Opera 的情况更为特殊,Function.prototype 被修改或扩充后,prototype 对象的 [[Enumerable]] 属性丢失或其值或被修改为 true,使得他也被枚举出来。
另外,Function.prototype 的 toString 方法被覆盖后依然无法被枚举,这证明了这个方法被做了特殊处理,即使被覆盖,其原始的 [[Enumerable]] 属性值依然不变。
综上所有情况可见:
对于数组,避免用 for...in 方式而采用索引即数字下标的形式枚举数组成员。
对于 Date String 以及其他对象,没有必要使用 for...in 来枚举它们的成员,因此一般不会有兼容性问题。
操作系统版本: | Windows 7 Ultimate build 7600 |
---|---|
浏览器版本: |
IE6
IE7 IE8 Firefox 3.6.13 Chrome 4.0.302.3 dev Safari 5.0.2 Opera 11.01 |
测试页面: | for_in_native_code.html |
本文更新时间: | 2011-02-18 |
Date Array String prototype property for in enumerable DontEnum 枚举 原型 属性