使用Object.prototype和Array.prototype属性的JavaScript for...in循环

11

我正在阅读MDN文档,以更好地理解Javascript。这是来自该文档的摘录。

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}

在最糟糕的情况下,我认为它会打印0, 1, 2, "foo", "arrCustom",但它还会打印objCustom

更新:
1)如何可视化从iterableArray一直到Object的原型链。就像是否有iterable.getParent方法或iterable.myparent属性指向其父级一样。
2)为什么不打印数组函数,例如toStringsort,它们也位于Array.prototype上。
3)当某人将某些内容添加到Array.prototype属性时,我是否需要始终使用hasOwnProperty


for循环遍历对象的所有可枚举属性,因为您没有将这些属性定义为不可枚举,所以它们会被遍历。 - Patrick Evans
我不确定我理解你的第一个问题。你说的“如何查看连接”是什么意思?iterable instanceof Array/iterable instanceof Object将显示它们继承自这些对象。如果你不知道一个对象继承自哪里,但想找出来,可以使用Object.getPrototypeOf(iterable) - Bergi
@Srinivas 嗯,谢谢。正如我所说,可以使用 Object.getPrototypeOf 实现这一点。另请参阅相似的问题。 - Bergi
@Srinivas 继续在该对象上调用 Object.getPrototypeOf 直到你到达 null(链的末尾)。请参见第三个重复项以获取示例代码。 - Bergi
谢谢@Bergi提供的支持性信息,我能让我的arrCustomobjCustom不可枚举吗? - Srinivas
显示剩余8条评论
3个回答

7

这是因为 for in 循环旨在迭代所有可枚举的属性,包括自有和继承的。您可以使用 Object.keys() 仅获取自有属性。

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

Object.keys(iterable).forEach(function(key) {
  console.log(key); // logs 0, 1, 2, "foo"
});

然而,在一个数组上放非数字属性是非常不寻常的。通常有更好的方法来完成您需要做的任何事情。
在数组上使用for-in循环也是不寻常的。只要将其限制为其数字索引,就有其他更好的迭代数组的方式。

1)“如何从可迭代对象可视化原型链一直到数组,最终到。是否有iterable.getParent方法或iterable.myparent属性指向它的父级?”

您可以使用Object.getPrototypeOf()方法获取对象继承的下一个对象。在循环中执行此操作,直到达到null为止。
var proto = Object.getPrototypeOf(myObj);
do {
  console.log(proto);
} while((proto = Object.getPrototypeOf(proto)));

2) "为什么不打印数组函数,比如toString、sort,它们也在Array.prototype上。"

toString()和其他内置方法是不可枚举的。正如我之前提到的,for in只能遍历到可枚举的属性。

3) "当有人向Array.prototype添加东西时,我需要总是使用hasOwnProperty吗?"

不要在数组上使用for in循环,这样做会更好。但是,如果您使用for in,您需要使用.hasOwnProperty()样板代码来保护它。

您还应该注意,在使用for in时,不能保证以数组索引顺序到达。而且通常比其他数组迭代方式慢得多。尤其是带有.hasOwnProperty()检查。


感谢您回答所有的问题,这对我帮助很大。我可以问一下您是从哪里学到这些知识的吗?能否向我指出一个不错的资源呢? - Suraj Jain

4

因为for-in循环遍历对象的所有属性,包括从原型继承的属性。要跳过继承的属性,请使用hasOwnProperty()

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i);
  }
}


1

for..in 循环遍历对象的所有属性,包括自身属性和继承属性。这就是为什么通常要使用 hasOwnPropertyfor..in 结合使用,像这样:

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'hello';

for (let i in iterable) {
  if (iterable.hasOwnProperty(i))
    console.log('own', i); // logs 0, 1, 2, "foo"
  else
    console.log('not', i); // logs "arrCustom", "objCustom" (inherited)
}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接