targetArray.reduce 在 reducer 函数中更改 targetArray.length 时的行为
targetArray.reduce behavior when targetArray.length is changed in the reducer function
这个问题主要针对那些使用 ECMAScript 规范的人 and/or 实施它。
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
有意在每次迭代时更新,而不是像规范中指定的那样从一开始就保持固定,这是否有具体原因?
您看到的行为是因为步骤 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);
或者通过在 .length
更改不影响属性的对象上调用 reduce
:
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);
这个问题主要针对那些使用 ECMAScript 规范的人 and/or 实施它。
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
有意在每次迭代时更新,而不是像规范中指定的那样从一开始就保持固定,这是否有具体原因?
您看到的行为是因为步骤 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);
或者通过在 .length
更改不影响属性的对象上调用 reduce
:
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);