'Calling a function directly vs using the apply/call method
In the following code to generate a not
function:
function not(func) {
return (...args) => !func(...args);
}
const even = x => x%2 === 0;
const odd = not(even);
let a = [1,2,3,4,5];
console.log(a, a.map(odd));
Is there any reason to use func(...args)
vs func.call(this, ...args)
? What might be a use case where the second would be a better option than the first (if ever)? And finally, is func.bind(this)(...args)
the same as func.call(this, ...args)
?
Another example would be the difference between the two ways of invoking it:
function compose(f, g) {
return function(...args) {
return f(g(...args)); // first
return f.call(this, g.apply(this, args)); // second
return f.bind(this)(g.bind(this)(...args)); // third
}
}
console.log(compose(x=>x*x, (x,y)=>x+y)(2,3));
Obviously the first one would be preferred if they're all essentially the same.
Solution 1:[1]
Because not
is using arrow notation to return its new function, if it contained the this
keyword its value would be whatever this
is when not
is called, rather than whatever this
is when the returned function is called.
The value of this
could be conserved if not
avoids using arrow notation, because functions created by arrow notation don't have their own this
or arguments
:
function not(func) {
return function (...args) {
return !func.apply(this, args);
}
}
Avoiding arrow notation also means you could pass through arguments
directly instead of using a rest parameter to gather them as an Array
:
function not(func) {
return function () {
return !func.apply(this, arguments);
}
}
Maintaining the value of this
is only important if you expect your not
function might be applied to functions that care about their this
value. But it's quite easy to maintain, and unless your use case requires something different there should be no harm in passing it through like this.
To answer your second question, no func.bind(this)(...args)
is not quite the same as func.call(this, ...args)
. Though the difference doesn't really matter so much if you're not saving the function returned by func.bind(this)
.
Function.prototype.bind creates a new version of a function which always has the same value for this
regardless of how that function is invoked. Function.prototype.call, on the other hand, only invokes a function in a particular way, it doesn't also create a new version of it first.
Solution 2:[2]
It makes a difference, if you use a prototype from a method like Set#has
.
In this case this
has to be preserved for the call, or better with apply
, because of having an array of arguments.
function not(func) {
return function(...args) { return !func.apply(this, args); };
// or with spreading !func.call(this, ...args);
}
const hasNot = not(Set.prototype.has);
let a = [1, 2, 3, 4, 5];
console.log(a.map(hasNot, new Set([1, 2, 3])));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Mark Hanna |
Solution 2 | Nina Scholz |