为何自定义Array.prototype方法会出现在for...in循环,原生方法却不会?
我为Array原型添加了如下方法:
Array.prototype.intersection = function(other) { return this.filter(x => other.indexOf(x) >= 0);}
随后我对数组进行遍历,示例如下:
a = [1, 2, 3] // 输出: (3) [1, 2, 3] for (let j in a) console.log(j) // 输出: // VM30274:1 0 // VM30274:1 1 // VM30274:1 2 // VM30274:1 intersection // undefined
根据Object.keys方法的定义:
Object.keys() returns an array whose elements are strings corresponding to the enumerable string-keyed property names found directly upon object. This is the same as iterating with a for...in loop, except that a for...in loop enumerates properties in the prototype chain as well. The order of the array returned by Object.keys() is the same as that provided by a for...in loop.
我理解intersection出现在遍历结果中的原因,也知道应使用keys()等方式遍历,但疑惑为何只有intersection被枚举,而push、pop等其他Array原型方法却没有?原生方法是否有特殊处理?
核心原因就是属性的可枚举性(enumerable)。
你直接给Array.prototype添加的方法,默认是**可枚举(enumerable: true)**的,所以会被for...in遍历到原型链上的这个属性。
而JS的原生数组方法(比如push、pop、shift这些),在定义的时候被设置成了不可枚举(enumerable: false)。你可以用Object.getOwnPropertyDescriptor验证一下:
// 查看自定义方法的属性描述 console.log(Object.getOwnPropertyDescriptor(Array.prototype, 'intersection')); // 输出大概是: { value: ƒ, writable: true, enumerable: true, configurable: true } // 查看原生push方法的属性描述 console.log(Object.getOwnPropertyDescriptor(Array.prototype, 'push')); // 输出大概是: { value: ƒ, writable: true, enumerable: false, configurable: true }
如果想让你自定义的原型方法也不被for...in遍历到,可以用Object.defineProperty来定义,手动把enumerable设为false:
Object.defineProperty(Array.prototype, 'intersection', { value: function(other) { return this.filter(x => other.indexOf(x) >= 0); }, enumerable: false, // 关键:设置为不可枚举 writable: true, configurable: true });
这样再用for...in遍历数组,就不会出现intersection了。
内容的提问来源于stack exchange,提问作者russell

