Reputation: 242
I know that adding a method to the prototype this way is not the best, but I'm just testing.
Array.prototype.maap = function (transform) {
let mapped = [];
for (let element of this) {
mapped.push(transform(element));
}
return mapped;
}
console.log([0, 2, 3].maap(n => n / this.length));
I am getting:
[NaN, Infinity, Infinity]. I think the problem is "this.length".
Upvotes: 2
Views: 87
Reputation: 107
I think the problem is on the arrow function (the param transform
), Yes, this.length
is the directly related questions, go deeper, it's a problem about arrow function,
An arrow function does not have its own
this
. Thethis
value of the enclosing lexical scope is used;
Simply put, where the arrow function defined where the this
point.
So, for your code, The parameters you passed in is n => n / this.length
, and it is defined in function console.log
in the environment of window
. So the real problem is:
transf = (n) => {
console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: Window, …}
return n / this.length
}
console.log([0, 2, 3].maap(transf));
Upvotes: 1
Reputation: 370659
this
inside an arrow function references the same this
in its containing block. Here, the containing block is the top level, where this
refers to window
, and window.length
is 0
.
console.log(this === window);
console.log(window.length);
So, your code is equivalent to:
Array.prototype.maap = function(transform) {
let mapped = [];
for (let element of this) {
mapped.push(transform(element));
}
return mapped;
}
console.log(this.length);
console.log([0, 2, 3].maap(n => n / 0));
0 / 0
is undefined
, while most any other number / 0
is Infinity
(or -Infinity
).
If you want to emulate Array.prototype.map
's behavior with this
, the second argument passed to maap
should be the this
value the callback is invoked with:
Array.prototype.maap = function(transform, thisVal) {
let mapped = [];
for (let element of this) {
mapped.push(transform.call(thisVal, element));
}
return mapped;
}
const arr = [0, 2, 3];
console.log(arr.maap(
function(n){ return n / this.length; },
arr
));
Upvotes: 1
Reputation: 385098
You're right, the problem is this.length
. The trouble is that it's not in the function! It's in a lambda, whose scope is not that of the array by which it's later invoked. As such, this
is not the array, and this.length
is a solid 0 (0/0 being NaN, 2/0 being infinity and 3/0 also being infinity).
You can either hardcode the real value 3
, or move your logic into the function itself. Or you could have the lambda (actually an "arrow function" in JavaScript) take another parameter: that of the denominator.
Array.prototype.maap = function (transform) {
let mapped = [];
for (let element of this) {
mapped.push(transform(element, this.length));
}
return mapped;
}
console.log([0, 2, 3].maap((n, m) => n / m));
Upvotes: 3