I'm creating a proxy of an array, and then calling .map on the proxy to iteratively retrieve the elements in the target array:
const proxiedArray = new Proxy([...], {
get: function(target, prop) {
console.log(target, prop) // This is just to see what properties I'm retrieving
return target[prop]
}
})
proxiedArray.map(el => ...)
Surprisingly, The log is:
[...] "map"
[...] "length"
[...] "constructor"
[...] "0"
[...] "1"
[...] "2"
[...] "3",
etc
I saw on this post that arrays can be 'wrapped transparently', which I assume is why .map works. But I see that then the proxy is asked for 3 properties: map, length, and constructor.
Why is this? (in particular, why is the constructor checked?)
When you do proxiedArray.map, you are accessing the "map" property from the object. This is why, that property gets logged first.
If you check the polyfill of Array.prototype.map, there is this code:
var len = O.length >>> 0
which is accessing current array's length. So, that explains the length property.
I'm not sure about the constructor property. I copied the polyfill of Array.prototype.map, added debugger inside it and executed your code. The constructor property was not logged.
It is probably coming from this bit A = new Array(len). Internally, javascript might be handling this part a bit differently than what the polyfill suggests (Something like A = new this.constrcutor(len) will access the constructor property)
Array.prototype.map = function(callback /*, thisArg*/ ) {
var T, A, k;
if (this == null) {
throw new TypeError('this is null or not defined');
}
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal
// method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 1) {
T = arguments[1];
}
// 6. Let A be a new array created as if by the expression new Array(len)
// where Array is the standard built-in constructor with that name and
// len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while (k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal
// method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal
// method of O with argument Pk.
kValue = O[k];
// ii. Let mappedValue be the result of calling the Call internal
// method of callback with T as the this value and argument
// list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor
// { Value: mappedValue,
// Writable: true,
// Enumerable: true,
// Configurable: true },
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, k, {
// value: mappedValue,
// writable: true,
// enumerable: true,
// configurable: true
// });
// For best browser support, use the following:
A[k] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
const proxiedArray = new Proxy([1, 2, 3], {
get: function(target, prop) {
console.log(prop) // This is just to see what properties I'm retrieving
return target[prop]
}
})
proxiedArray.map(el => el)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With