For learning purpose, I wrote a piece of (meaningless) code like this:
Function.prototype.invoke = function(...args) {
return this(...args);
}
const foo = (a, b) => a + b;
console.log(foo.invoke(1, 2)); // 3, all right!
const arr = [];
arr.push.invoke(1,2); // TypeError: Cannot convert undefined or null to object
console.log(arr);
Here I define a method on Function
's prototype named invoke
, which is used to just invoke a function by foo.invoke(args)
(instead of the conventional way foo(args)
). I wonder why foo
runs while arr.push
can't.
As far as I know, this result from the this
problem. this
in my invoke
method is push
, but this
's this
(push
's caller) is window
, which is not a array-like object(?). But why the error is Cannot convert undefined or null to object
?
What on earth is the reason for this error? Is there any way to correct it?
arr.push
is the same function as Array.prototype.push
, and Array.prototype.push
requires a calling context to identify which array the argument(s) are going to be pushed to. With
arr.push(1, 2);
the calling context (what comes before the .
when the function is invoked) is arr
. But with your invoke
there is no calling context:
return this(...args);
For the same reason, you can't call
push
on undefined
:
Array.prototype.push.call(undefined, 1, 2);
If you want to "invoke" a function which requires a calling context, maybe pass the this
value as the first argument and use .call
:
Function.prototype.invoke = function(thisVal, ...args) {
return this.apply(thisVal, args);
}
const foo = (a, b) => a + b;
console.log(foo.invoke(undefined, 1, 2)); // 3, all right!
const arr = [];
arr.push.invoke(arr, 1,2);
console.log(arr);
You can also bind
the arr.push
to arr
before calling invoke
:
Function.prototype.invoke = function(...args) {
return this(...args);
}
const foo = (a, b) => a + b;
console.log(foo.invoke(1, 2)); // 3, all right!
const arr = [];
arr.push.bind(arr).invoke(1,2);
console.log(arr);