如何区分原生原型与扩展原型,遍历数组时跳过扩展属性?
这是个非常常见的JS坑——for...in会遍历对象自身以及原型链上的所有可枚举属性,所以你添加到Array.prototype的repeat方法也被当成遍历项输出了。下面给你几种实用的解决办法:
1. 用hasOwnProperty()过滤原型属性
hasOwnProperty()是对象的原生方法,专门用来判断属性是否属于对象自身(而非从原型链继承)。修改你的循环代码即可:
var model = { features:[1,2,3] }; for (var p in model.features) { // 只处理数组自身的属性 if (model.features.hasOwnProperty(p)) { console.log(p); } }
这样就能精准跳过原型上的repeat,只打印数组自身的索引。
2. 用Object.keys()遍历自身可枚举属性
ES6引入的Object.keys()会返回对象自身所有可枚举属性的数组,完全不会包含原型链上的内容。结合forEach遍历更简洁:
var model = { features:[1,2,3] }; Object.keys(model.features).forEach(function(p) { console.log(p); });
这种写法比for...in加判断更符合现代JS的风格,也更不容易出错。
3. 直接用数组原生遍历方法(推荐)
既然你遍历的是数组,优先用数组专属的遍历方法才是正道——比如forEach、for...of,它们只会遍历数组的元素/索引,完全不会碰原型链上的属性:
// 如果想打印数组元素(对应你预期的1、2、3) model.features.forEach(function(item) { console.log(item); }); // 如果想打印索引(0、1、2) for (const index of model.features.keys()) { console.log(index); }
这种方法从根源上避开了for...in的原型遍历问题,逻辑也更清晰。
4. 从源头阻止自定义原型属性被枚举(可选)
如果这个repeat方法是你自己添加的(或者能协调第三方库修改),可以用Object.defineProperty()定义属性——它默认会把属性设为不可枚举:
Object.defineProperty(Array.prototype, 'repeat', { value: function(value, length) { while (length) this[--length] = value; return this; }, // 显式声明不可枚举(默认就是false,写出来更直观) enumerable: false });
这样即使你用for...in遍历数组,也不会出现repeat这个属性了。
内容的提问来源于stack exchange,提问作者ParoX
相关产品推荐
相关产品推荐

