Array对象原型新增方法导致的for...in遍历问题与解决方案

问题

为了方便调用,我们一般都会定义一些自定义的对象原型方法,比如下面这个:

Array.prototype.remove = function (callback) {
    const index = this.findIndex(callback);
    if (index > -1) {
      this.splice(index, 1);
    }
    return index;
  }

上面的代码定义了一个数组的删除方法,调用方便快捷。由于是定义在对象原型上,那就意味着所有的数组对象都具备这个方法。然而我们在用for...in去遍历这个数组的时候,就会导致remove的方法名也被遍历出来,如下:

for(let i in ['a','b','c']){
	console.log(i)
}
// 0
// 1
// 2
// remove

导致出现这种情况的原因在于我们通过上面那种方式去添加自定义对象原型方法的时候,该方法在原型链上默认是可枚举的属性。而for...in 循环会遍历对象的恰恰是可枚举的属性,包括对象的原型链上的属性。

数组的原型链

数组也是对象,因此它们也遵循原型链的概念。在 JavaScript 中,数组是通过构造函数 Array 创建的对象。数组的原型是 Array.prototype。而 Array.prototype 的原型是 Object.prototype,最终 Object.prototype 的原型是 null,形成了原型链。

需要注意的是,数组具有自己的一些方法,例如 pushpopforEach 等,这些方法是定义在 Array.prototype 上的。因此,当你使用数组的方法时,实际上是通过原型链找到这些方法。这里 pushforEach 方法都是通过原型链从 Array.prototype 继承而来的。原型链的概念使得 JavaScript 中的对象能够实现继承和共享方法。

解决方案

解决思路有两种,一种是通过别的遍历方式去替代for...in,另一种则是确保自定义对象原型方法不被遍历

方法一 替代for…in

我们可以使用 for...of 循环或 Array.forEach 方法,它们只会遍历数组的实际元素,而不包括原型链上的属性。

const myArray = [1, 2, 3];

// 使用 for...of 循环
for (const element of myArray) {
  console.log(element); // 输出 1, 2, 3
}

// 或者使用 forEach 方法
myArray.forEach(element => {
  console.log(element); // 输出 1, 2, 3
});

方法二 确保自定义对象原型方法不被遍历

为了确保自定义原型方法不被遍历,拿主要的思路就是将这个方法改为不可枚举的属性。我们可以通过 Object.defineProperty 来定义。通过修改不可枚举属性不仅不会出现在 for...in 循环中,也不会被 Object.keys()Object.values()Object.entries() 包含。这样,就可以在原型上定义方法,但不会在常见的遍历方法中暴露出来。

Object.defineProperty(Array.prototype, "remove", {
  value(callback) {
    const index = this.findIndex(callback);
    if (index > -1) {
      this.splice(index, 1);
    }
    return index;
  },
  enumerable: false, // 将属性设置为不可枚举
  writable: true,
  configurable: true
});


for(let i in ['a','b','c']){
	console.log(i)
}
// 0
// 1
// 2

可以通过Object.getOwnPropertyDescriptor查看对象原型属性是否可以枚举:

Object.getOwnPropertyDescriptor(Array.prototype,'remove');
//{writable: true, enumerable: false, configurable: true, value: ƒ}
Object.getOwnPropertyDescriptor(Array.prototype,'push');
//{writable: true, enumerable: false, configurable: true, value: ƒ}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值