首页 > 解决方案 > 枚举对象属性

问题描述

ecma262规范有一个名为13.7.5.15EnumerateObjectProperties的标题,从它的名字我们可以理解,它负责枚举对象中的属性。这个“半算法”说对象必须遵循以下规则(我不会全部列出,因为其余的都很明显):

  1. 迭代器的 throw 和 return 方法是 null 并且永远不会被调用。

如果我正确理解了所有内容,那么迭代器应该返回 null,并且在尝试调用这些方法时返回 undefined。尽管这可能意味着迭代器没有这些方法,并且它们实际上是空的,并且不具有 null 类型的空值。

  1. 枚举期间可以删除目标对象的属性。在迭代器的 next 方法处理之前删除的属性将被忽略。

是的,在枚举过程中确实可以删除该属性(意思是 for...in/of)。

/// Deletion properties on object
var arr = {a:111,b:222,c:333,d:444,e:555,f:666,g:777,h:888,i:999};
for(var item in arr){
    if(item == "c") delete arr["c"];
    if(item == "e") delete arr["e"];
    if(item == "h") delete arr["h"];
    console.log(arr[item]); /// when we will be on property "c", we can delete it, it's will accomplished successfull
}
console.log(arr);

但是第二句话让我很困惑。据说在迭代器处理 next 方法之前删除的属性将被忽略。你能证明这样的例子吗?由于某种原因,我陷入了混乱,无法做到。

  1. 如果在枚举过程中向目标对象添加了新属性,则不保证在活动枚举中处理新添加的属性

这是真的(至少在 chrome 中):

/// Addition properties on object
var arr = {a:111,b:222,c:333,d:444,e:555,f:666,g:777,h:888,i:999};
for(var item in arr){
    if(item == "c") arr["c1"] = 1;
    if(item == "e") arr["e1"] = 1;
    if(item == "h") arr["h1"] = 1;
    console.log(arr[item]);
}
console.log(arr);

  1. EnumerateObjectProperties 必须通过调用其 [[OwnPropertyKeys]] 内部方法来获取目标对象自己的属性键。

在我看来,这是本段中的重要陈述之一。如您所知, [[OwnPropertyKeys]] 定义了属性在对象中列出的顺序。因此,我们看一下标题的第二段:

枚举属性的机制和顺序没有指定,但必须符合下面指定的规则。

嗯?什么?你能解释一下什么鬼吗?

标签: javascriptecmascript-6

解决方案


据说在迭代器处理 next 方法之前删除的属性将被忽略。

这意味着您可以在迭代期间删除尚未到达的元素,然后将不会枚举它们:

const obj = { a: 1, b: 2, c: 3 };


for(let prop in obj) {
  console.log('prop', prop);
  delete obj.b;
}

这实际上与您可以使用for of循环和执行的任何操作不同Object.entries()

const obj = { a: 1, b: 2, c: 3 };


for(let [prop] of Object.entries(obj)) {
  console.log('prop', prop);
  delete obj.b;
}

枚举属性的机制和顺序没有指定,但必须符合下面指定的规则。

引擎在这里有一些自由。有一些规则要遵循,但例如,引擎选择枚举原型链的顺序似乎是开放的。它必须调用[[OwnPropertyKeys]]并不意味着它不允许在处理之前诉诸结果。


推荐阅读