使用get处理程序在代理上调用时,Array.prototype.forEach()不起作用

Mic*_*ski 6 javascript iteration foreach ecmascript-6 es6-proxy

我有以下代理:

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);
  },
});
Run Code Online (Sandbox Code Playgroud)

它是一个类似于数组的对象,因为它具有数字属性和length指定元素数量的属性.我可以使用for...of循环迭代它:

for (const element of p) {
  console.log(element); // logs 'one' and 'two'
}
Run Code Online (Sandbox Code Playgroud)

但是,该forEach()方法不起作用.

p.forEach(element => console.log(element));
Run Code Online (Sandbox Code Playgroud)

此代码不记录任何内容.永远不会调用回调函数.为什么它不起作用,我该如何解决?

代码段:

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));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

Mic*_*ski 6

for...of循环之间的区别之一Array.prototype.forEach()是前者使用@@iterator属性循环对象,而后者将属性从0to 迭代length,并且仅当对象具有该属性时才执行回调.它使用[[HasProperty]]内部方法,在这种情况下返回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));
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
Run Code Online (Sandbox Code Playgroud)