Array.prototype.forEach() 在使用 get 处理程序的代理上调用时不工作
Array.prototype.forEach() not working when called on a proxy with a get handler
我有以下代理:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
它是一个类似数组的对象,因为它具有数值属性和 length
属性 指定元素的数量。我可以使用 for...of
循环对其进行迭代:
for (const element of p) {
console.log(element); // logs 'one' and 'two'
}
但是,forEach()
方法不起作用。
p.forEach(element => console.log(element));
此代码不记录任何内容。永远不会调用回调函数。为什么它不起作用,我该如何解决?
代码片段:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
console.log('for...of loop:');
for (const element of p) {
console.log(element);
}
console.log('forEach():');
p.forEach(element => console.log(element));
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
for...of
循环和Array.prototype.forEach()
的区别之一是前者使用@@iterator
属性循环遍历对象,而后者迭代从 0
到 length
的属性,并且仅当对象具有 属性 时才执行回调。它使用 [[HasProperty]]
内部方法,在本例中,每个数组元素都使用 returns false
。
解决方案是同时添加 has()
处理程序,它将拦截 [[HasProperty]]
调用。
工作代码:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
has(target, property) {
if (['0', '1', 'length'].includes(property)) return true;
return Reflect.has(target, property);
},
});
p.forEach(element => console.log(element));
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
还有一个比较简单的附加选项。使用 Array.from()
生成一个可以迭代的数组。
const a = Array.from(p);
a.forEach(element => console.log(element));
完整代码:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
const a = Array.from(p);
a.forEach(element => console.log(element));
我有以下代理:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
它是一个类似数组的对象,因为它具有数值属性和 length
属性 指定元素的数量。我可以使用 for...of
循环对其进行迭代:
for (const element of p) {
console.log(element); // logs 'one' and 'two'
}
但是,forEach()
方法不起作用。
p.forEach(element => console.log(element));
此代码不记录任何内容。永远不会调用回调函数。为什么它不起作用,我该如何解决?
代码片段:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
console.log('for...of loop:');
for (const element of p) {
console.log(element);
}
console.log('forEach():');
p.forEach(element => console.log(element));
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
for...of
循环和Array.prototype.forEach()
的区别之一是前者使用@@iterator
属性循环遍历对象,而后者迭代从 0
到 length
的属性,并且仅当对象具有 属性 时才执行回调。它使用 [[HasProperty]]
内部方法,在本例中,每个数组元素都使用 returns false
。
解决方案是同时添加 has()
处理程序,它将拦截 [[HasProperty]]
调用。
工作代码:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
has(target, property) {
if (['0', '1', 'length'].includes(property)) return true;
return Reflect.has(target, property);
},
});
p.forEach(element => console.log(element));
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
还有一个比较简单的附加选项。使用 Array.from()
生成一个可以迭代的数组。
const a = Array.from(p);
a.forEach(element => console.log(element));
完整代码:
const p = new Proxy({
[Symbol.iterator]: Array.prototype.values,
forEach: Array.prototype.forEach,
}, {
get(target, property) {
if (property === '0') return 'one';
if (property === '1') return 'two';
if (property === 'length') return 2;
return Reflect.get(target, property);
},
});
const a = Array.from(p);
a.forEach(element => console.log(element));