这个问题主要针对那些使用ECMAScript规范和/或实现它的人。
spec指定Array.prototype.reduce(callbackfn[,initialValue])
的算法。
看到算法第2步读取了Let len be ? ToLength(? Get(O, "length"))
,此后,我的理解是len
再也不会更新了。但是,请看以下内容:
const a = [0,1,2,3,4];
a.reduce(p=>{
a.splice(0,1);
console.log(a);
return p;
},a);
// Logs:
// [1,2,3,4]
// [2,3,4]
// [3,4]
// and that's it
由于迭代应该运行while k<len
(k
是迭代计数器),因此此行为表明,在我尝试的实现中(Chrome,Edge,Node),len
在每次迭代中被更新为当前迭代的a
长度。
这真的是预期的行为吗?是否有具体的原因为何len
会在每次迭代中有目的地进行更新,而不是像规范中指定的那样从一开始就将其固定?
答案 0 :(得分:3)
您看到的行为是由于步骤9.2引起的:仅当对象上存在属性时才调用回调。它确实重复了5次,但是删除了3个元素之后,在第四次和第五次迭代中a.hasOwnProperty(3)
和a.hasOwnProperty(4)
为假。
我们最好用代理来证明这一点:
const a = [0,1,2,3,4];
new Proxy(a, {
has(target, p) { const v = Reflect.has(target, p); console.log("has", p, v); return v },
get(target, p) { const v = Reflect.get(target, p); console.log("get", p, v); return v }
}).reduce((p, e) => {
a.length--;
console.log("at " + e, a);
return p;
}, null);
或者通过在其reduce
更改不影响属性的对象上调用.length
:
const a ={0:0,1:1,2:2,3:3,4:4,length:5,reduce:Array.prototype.reduce};
a.reduce((p, e) => {
a.length--;
console.log("at " + e, a);
return p;
}, null);