【问题标题】:How is for...in implemented in JavaScript?for...in 是如何在 JavaScript 中实现的?
【发布时间】:2012-11-19 20:33:16
【问题描述】:
我看到一个关于 for...in 语句的iteration order 的问题,并警告说该命令不能被信任。当前节点和访问节点的迭代和跟踪在内部是如何完成的,在 JavaScript 引擎之间有何不同?
【问题讨论】:
标签:
javascript
algorithm
object
cross-browser
iteration
【解决方案1】:
来自the MDN documentation for for...in(已添加重点):
以任意顺序遍历对象的可枚举属性。
我确信内部细节因 JavaScript 引擎而异,甚至很可能在任何特定引擎的版本之间。我猜在许多引擎中,它是通过某种哈希表实现来完成的。由于哈希函数会随着哈希表的增长对键重新排序,因此属性a 和b 的相对顺序可以通过添加新属性c 来改变,而无需更改引擎或任何东西。
【解决方案2】:
看来Object.keys() 和Object.defineProperties 的实现应该模仿for...in 的行为:
如果实现为 for-in 语句定义了特定的枚举顺序,则该算法的第 5 步必须使用相同的枚举顺序。
所以它们可以作为参考。
delete 运算符也可以使事情复杂化:
未指定枚举属性的机制和顺序(第一个算法中的步骤 6.a,第二个算法中的步骤 7.a)。被枚举对象的属性可能在枚举过程中被删除。如果在枚举期间还没有访问过的属性被删除,那么它就不会被访问。如果在枚举过程中向正在枚举的对象添加了新属性,则不能保证在活动枚举中访问新添加的属性。一个属性名称在任何枚举中都不能被多次访问。
原型链中的名称冲突也是如此:
枚举一个对象的属性包括递归地枚举其原型的属性、原型的原型等等;但是如果原型的属性被“隐藏”,则不会枚举它,因为原型链中的某些先前对象具有同名的属性。在确定原型对象的属性是否被原型链上的前一个对象遮蔽时,不考虑 [[Enumerable]] 属性的值。
参考文献