admin管理员组文章数量:1244249
I have the following 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);
},
});
It's an array-like object, because it has numeric properties and the length
property specifying the amount of elements. I can iterate it using a for...of
loop:
for (const element of p) {
console.log(element); // logs 'one' and 'two'
}
However, the forEach()
method is not working.
p.forEach(element => console.log(element));
This code doesn't log anything. The callback function is never called. Why isn't it working and how can I fix it?
Code snippet:
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=".16.0/polyfill.min.js"></script>
I have the following 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);
},
});
It's an array-like object, because it has numeric properties and the length
property specifying the amount of elements. I can iterate it using a for...of
loop:
for (const element of p) {
console.log(element); // logs 'one' and 'two'
}
However, the forEach()
method is not working.
p.forEach(element => console.log(element));
This code doesn't log anything. The callback function is never called. Why isn't it working and how can I fix it?
Code snippet:
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./ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
Share
Improve this question
asked Nov 3, 2016 at 18:35
Michał PerłakowskiMichał Perłakowski
92.6k30 gold badges163 silver badges186 bronze badges
2
- You could just extend Array to not polyfill each and every feature that can bee broken when being proxified. – Estus Flask Commented Nov 3, 2016 at 18:56
- @estus I could, but that doesn't fix it. – Michał Perłakowski Commented Nov 3, 2016 at 19:20
3 Answers
Reset to default 8One of the differences between a for...of
loop and Array.prototype.forEach()
is that the former uses the @@iterator
property to loop over the object, while the latter iterates the properties from 0
to length
, and executes the callback only if the object has that property. It uses a [[HasProperty]]
internal method, which in this case returns false
for every array element.
The solution is to add also the has()
handler, which will intercept the [[HasProperty]]
calls.
Working code:
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./ajax/libs/babel-polyfill/6.16.0/polyfill.min.js"></script>
There is an additional option that is relatively simple. Use Array.from()
to generate an array that you can iterate over.
const a = Array.from(p);
a.forEach(element => console.log(element));
The full code:
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));
if targetObject
is of form [{a:1, b:2}, {a: 3, b:4}, {a: 5, b: 6}]
to add sudoKey
to each object we can below proxy
let proxy_array = new Proxy(targetObjectArray, {
get: function (target, key) {
if (!isNaN(parseInt(key))) {
return { sudoKey: pute(), ...Reflect.get(target, key)}
}
return Reflect.get(target, key);
}
});
Example
let x = [{a: 1, b:2}, {a:3, b:4}, {a:5, b: 6}]
let y = new Proxy(x, {
get: function (target, key) {
if (!isNaN(parseInt(key))) {
return { c: -1, ...Reflect.get(target, key)}
}
return Reflect.get(target, key);
}
});
y.forEach(e => console.log(e))
Output:
{c: -1, a: 1, b: 2}
{c: -1, a: 3, b: 4}
{c: -1, a: 5, b: 6}
here !isNaN(parseInt(key))
is to to check whether prop
is ArrayIndex
(0, 1, 2 ... x.length - 1) or Array.Prototype
keys which include forEach as a property
MDN for Array.prototype which attach forEach the proxy Array
版权声明:本文标题:javascript - Array.prototype.forEach() not working when called on a proxy with a get handler - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1740216235a2242915.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论