所以,这有效(至少在chrome中):
var foo = {
0: 'a',
1: 'b',
2: 'c'
};
//add a non-enumerable length property
Object.defineProperty(foo, 'length', {value: 3});
[].forEach.call(foo, function(val){console.log(val);}); //logs a b c
如果键是数字字符串而不是整数,它甚至可以工作,只要有一个length属性。但是,如果键是非数字字符串,则它会无声地失败。如果某些键是数字的,有些键是否适用于数字键,而在其他键上无声地失败。所以我的问题是双重的。首先,为什么我不能用非数字字符串执行此操作(底层实现是否使用递增for
循环?为什么它足够聪明,然后在键上进行类型强制?)
我的意思是,javascript没有真正的数组,对吧?它们只是用整数作为键的哈希表查找?因此,尽管我意识到我在这里将语言扩展到了突破点,为什么不能以正确的多态方式实现/破解这种行为呢?
第二个问题是,如果不应该/能够使其工作,谁认为让它失败默默是个好主意?为什么这不会引发错误?
答案 0 :(得分:1)
它仅适用于0
和length
之间的整数键,因为Array.prototype.forEach
应该与类似数组的对象一起使用。
底层实现是否使用递增for循环?
或多或少。其行为在ES5 Section 15.4.4.18:
中定义
- 让
O
成为调用ToObject
传递此值作为参数的结果。- 让
lenValue
成为使用参数“[[Get]]
”调用O
length
内部方法的结果。- 让
len
成为ToUint32(lenValue)
。- 如果
IsCallable(callbackfn)
为false
,则抛出TypeError
例外。- 如果提供了
thisArg
,请T
为thisArg
;其他请T
为undefined
。- 让
k
成为0
。- 重复,同时
k < len
- 让
Pk
成为ToString(k)
。- 让
kPresent
成为使用参数[[HasProperty]]
调用O
Pk
内部方法的结果。- 如果
kPresent
是true
,那么
- 让
kValue
成为使用参数[[Get]]
调用O
Pk
内部方法的结果。- 使用
[[Call]]
作为callbackfn
值{和}参数列表,将T
内部方法this
称为kValue
,k
和{ {1}}。O
增加k
。- 返回
醇>1
。
为什么它适用于非数组对象?
它的设计表现如下:
undefined
函数是故意通用的;它不需要 它的这个值是一个Array对象。因此它可以 转移到其他种类的对象用作方法。是否forEach
函数可以成功应用于宿主对象 实现相关的。
为什么不为非数字属性调用forEach
?
非数字属性“失败”,因为callbackfn
只是一个数组方法,其目的是迭代类似数组的对象。如果要迭代对象的所有属性,则应该使用forEach
循环。