我看到一个关于for...in语句迭代顺序的问题,并警告说不能信任顺序。在JavaScript引擎中,当前和已访问节点的迭代和跟踪是如何内部完成的?它们之间有什么不同?
我看到一个关于for...in语句迭代顺序的问题,并警告说不能信任顺序。在JavaScript引擎中,当前和已访问节点的迭代和跟踪是如何内部完成的?它们之间有什么不同?
for...in
文档(强调添加)中可以看出:
我相信在JavaScript引擎中,内部细节会有所不同,甚至在任何特定引擎的版本之间也可能不同。我猜想,在许多引擎中,它是通过某种哈希表实现的。由于哈希函数会重新排列键,随着哈希表的增长,例如属性以任意顺序迭代对象的可枚举属性。
a
和b
的相对顺序可能会因添加一个新属性c
而改变,而无需更改引擎或其他任何内容。看起来,Object.keys()
和Object.defineProperties
的实现应该模仿for...in
的行为:
如果一个实现定义了for-in语句的特定枚举顺序,则该枚举顺序必须在此算法的第5步中使用。
因此它们可以用作参考。
delete
运算符也可能会使事情复杂:
枚举属性的机制和顺序(第一个算法的6.a步骤,第二个算法的7.a步骤)未指定。正在枚举的对象的属性可能在枚举过程中被删除。如果删除了尚未在枚举过程中访问的属性,则不会访问该属性。如果在枚举过程中向正在枚举的对象添加新属性,则不能保证会在活动枚举中访问新添加的属性。任何枚举中都不得多次访问属性名称。
原型链中的名称冲突也可能会出现问题:
枚举对象的属性包括递归地枚举其原型、原型的原型等属性;但是,如果原型链中的某个先前对象具有相同名称的属性,则不会枚举原型的属性。在确定原型对象的属性是否被原型链上的先前对象遮蔽时,不考虑[[Enumerable]]属性的值。 参考资料