在循环中访问时,JS Prototype方法的行为不同

时间:2018-02-06 05:24:32

标签: javascript arrays prototype

我正在使用一个名为custommethod的新方法扩展数组对象,如下所示,并循环遍历数组中的值。但是,循环索引还会打印property的名称,该名称通过Array.prototype.<method>进行扩展。

Array.prototype.custommethod = function() {
    console.log("Hello from Custom Method");
}

Object.defineProperty(Array.prototype, "anothercustommethod", {
    value: function() {
        console.log("Hello from Another Custom Method");
    }
});

循环遍历数组

> x = [1,2]
[ 1, 2 ]

> for (i in x) { console.log(i); }
0
1
custommethod
  • 为什么anothercustommethod不会在此循环中打印出来?

  • 使用Object.defineProperty()更安全的方式创建Array.prototype

我很好奇javascript中的for循环是如何工作的。它是否在内部使用Object.keys()?如果是这样,它如何打印custommethod属于__proto__属性但不打anothercustommethod哪个属于__proto__属性?

2 个答案:

答案 0 :(得分:5)

为什么不会在此循环中打印另一个自定义方法?

for in遍历这些属性,数据描述符enumerable设置为true。

Documentation

  

<强>枚举   当且仅当此属性在期间出现时才返回true   枚举相应对象的属性。默认为   假的。

使用defineProperty时,您还可以传递额外的属性 - 可枚举。 默认情况下,它设置为false。

Array.prototype.custommethod = function() {
    console.log("Hello from Custom Method");
}

Object.defineProperty(Array.prototype, "anothercustommethod", {
    value: function() {
        console.log("Hello from Another Custom Method");
    },
    enumerable: true
});

const x = [1,2]
for (i in x) { console.log(i); }

使用Object.defineProperty()创建Array.prototype更安全吗?

没有任何关于安全的事情。尝试很少改变原型中的构建

答案 1 :(得分:0)

您可以通过此API检查该属性:

Object.getOwnPropertyDescriptor(Array.prototype,'custommethod');//{value: ƒ, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(Array.prototype,'anothercustommethod');//{value: ƒ, writable: false, enumerable: false, configurable: false}

见?得到的第一个:enumerable:true,第二个得到:enumerable:false,

其他值也不同,因为默认设置在由不同的API

设置时是不同的

实际上,想要更安全,可以使用此API:

Object.getOwnPropertyNames

Object.getOwnPropertyNames(Array.prototype).filter(v=>v.endsWith('custommethod'));//["custommethod", "anothercustommethod"]

如果有符号,您仍然需要

Object.getOwnPropertySymbols(Array.prototype);//[Symbol(Symbol.iterator), Symbol(Symbol.unscopables)]

Object.keys的作用与in一样,它们不会遍历其枚举为false的属性;

当您尝试使用其他API遍历属性时,应该考虑这些事情