I am curious how bounded call function works inside in Javascript. The confusing example:
Number.call.bind(Array)(undefined, 1, 2)
Output:
[1, 2]
Indeed, instead of Number I can write any function and that will be ignored. My assumption is at some moment Array is called as a constructor function and 1 and 2 are passing as parameters. My question is what inside of call function leads to such a strange behavior?
Thanks.
call is not much different from any other function (expect it can set this somehow). Here is a pseudo-code pseudo-version of call:
function call(thisArg, ...args) {
let boundThis = this.bind(thisArg);
return boundThis(...args);
}
So, all it really does is setting this of the function to the fist argument passed and then passes the remaining arguments to the function.
call.bind(Array) binds this inside call to Array, i.e. it "fixes" the function to which .call is applied to Array, meaning it will now always call Array. So you essentially have
let boundThis = Array.bind(thisArg);
return boundThis(...args);
which is basically Array(...args).
The first parameter in Function.prototype.bind() is the "thisArg" with which the bound function is called. Since the bound function in your example is Function.prototype.call(), that effectively returns a bound version of call() such that it is equivalent to Array.call(). The first argument for call() is the "thisArg" (yet again) with which the called function is called, and the rest are the parameters passed into the function. So now we're at Array(1, 2), and that returns your output.
What you're doing, via bind, is no different from:
Number.call.call(Array, undefined,1, 2);
The above sends four parameters to the call on the right, the first of which is the context to call the call on the left. Thus, after the call on the right finishes, the code factors to:
Array.call(undefined,1, 2);
Which factors to:
Array(1, 2);
Notice that Array is actually the function being called.
It could be any other function rather than a constructor:
Number.call.call(alert, window,"hello world");
Related
I'm following a tutorial by Tyler McGinnis on execution contexts, call stacks and closures.
https://www.youtube.com/watch?v=Nt-qa_LlUH0&feature=emb_title
I'm a bit confused with the closure example. I understand a closure is when a function is inside another function. I also understand that the inner function has access to the parent functions arguments (As explained in the video).
My confusion is in the code below is when makeAdder(5) is invoked is the inner function not invoked aswell on the first invokation? Tyler appears to suggest makeAdder is popped off the call stack when first invoked just leaving the inner function untouched.
The second part I don't understand when we call add5(2) this is invoking makeAdder(5) no? How do we add 2 arguments when the parent function only accepts one?
If someone could walk it through step by step of how it's all invoked that would be great!
var count = 0;
function makeAdder(x) {
return function inner(y) {
return x + y;
}
}
var add5 = makeAdder(5);
console.log(add5); // what the call to makeAdder returns
count += add5(2);
console.log(count);
when makeAdder(5) is invoked, is the inner function not invoked as well on the first invocation?
No, it isn't. Only makeAdder is invoked at that time, and makeAdder is not making any calls itself. It merely returns an object, and that object happens to be a function. And returning a function is done without actually invoking it.
when we call add5(2) this is invoking makeAdder(5) no?
It is not invoking makeAdder(5). Earlier on add5 was the result of calling makeAdder(5), and so add5 is that inner function. The special thing happening here is that when you call add5, an "execution context" is restored, which represents the state of affairs inside makeAdder at the moment it returned the function. This practically means that when add5 (the inner function) references the x variable, it will find the value in x it had at the moment makeAdder had been called earlier on.
How do we add 2 arguments when the parent function only accepts one?
Indeed, when we call the parent function, the second argument is not known yet, and we don't need to know it at that moment, since the inner function is not yet executed at that moment. The important thing with the call of the parent function, is that we establish the value of x, which will "live on", even though it can only be accessed by calling the inner function.
And when we call the inner function, we provide the second argument that is needed. The inner function can then combine the "magical" reference it has to the x value (provided when we made the parent call), with the normal argument it receives itself.
A simple way to look at this is as a function that returns a function--which can be called like a normal function because it is. So the first call of the function return type is a function.
Look the following example
function add(x,y){
return x+y;
}
function subtract(x,y) {
return x-y;
}
function calculator(type){
if(type ==='add'){
return add ; //here we are returning a function - the above add function
}
if (type==='subtract')
{
return subtract; // we are returning a function - the above subtract function
}
return null;
}
var fn = calculator('add'); // this call will return the function add which can be called as in below
var result = fn(4,5);
console.log(result) ; ///should print 9
Likewise the first call
var add5 = makeAdder(5);
returns a function which is exactly
function inner(y) { return x+5);
Then you can call add5(2) which essentially execute the above function.
I'm trying to understand the below code which prevents bugs caused by a function silently passing to a call back function more arguments that aren't wanted in the parameters of the callback function:
["1","2","3"].map(parseInt)
returns [1, NaN, NaN] because the index gets passed as a second parameter to parseInt which accepts it as the radix, so the array values are invalid. To solve it, the author of this blog post suggests a js extension:
Function.prototype.only = function(numberOfArgs) {
var self = this; //the original function
return function() {
return self.apply(this,[].slice.call(arguments,0,numberOfArgs))
}
};
Which would be called like so:
["1","2","3"].map(parseInt.only(1))
I'm struggling to understand why "this" is passed as a function parameter while self is returned as a reference to this. They both point to parseInt correct? Is there a difference in binding times of parameters vs return values?
They both point to parseInt correct?
No.
The value of this depends on how a function is called.
The function passed to map gets called by the internals of map.
Look at the documentation for map.
If a thisArg parameter is provided to map, it will be used as callback's this value. Otherwise, the value undefined will be used as its this value.
So if the returned anonymous function used this instead of self it would be calling undefined.apply not parseInt.apply.
I'm struggling to understand why "this" is passed as a function parameter while self is passed as a reference to this. They both point to parseInt correct?
No. self will refer to parseInt. this will be whatever this the function was called with, which could be anything. In your example:
["1","2","3"].map(parseInt.only(1))
...this will either be a reference to the global object (in loose mode) or undefined (in strict mode), because map will use undefined when calling the callback (which is turned into a reference to the global object in loose mode).
There are several ways this might be something else though:
If a second argument were passed to map:
["1","2","3"].map(parseInt.only(1), {})
// Second argument -----------------^^
...it would use that value rather than undefined when calling the callback.
If Function#bind were used on the function only returns:
["1","2","3"].map(parseInt.only(1).bind({}))
// Bind ---------------------------^
...then this would be that value.
If the function only returns were called with call or apply (which is what map does, so this is kind of a repetition of #1 :-) ), the value supplied for this would be used.
isInSet requires two arguments, but binds passes only theSet as first argument. I am not able to figure out how bind method works in this case
function isInSet(set , person) {
return set.indexOf(person.name) > -1;//checks for existence of person.name in theSet
}
console.log(ancestry .filter(function(person) {
return isInSet( theSet , person) ;
}) ) ;
// ! [{ name : " Maria van B r u s s e l " , ...} ,
// { name : " Carel H a v e r b e k e " , ...}]
console.log(ancestry.filter(isInSet.bind(null, theSet))) ;//**how does this work?**
// !... same result
bind() creates a new function from the function that it is called on. It sets the this keyword in the newly created function to be the first argument that you pass it (if null is passed, then it does not overwrite the default this keyword). You can also pass in extra arguments to bind() and if you do, they will always be inserted into the new function. So for instance, let's say you have a sum function that takes 2 arguments.
function sum (a, b) {
return a + b;
}
Now we could create a new function from this using bind() and always pass in one argument.
var boundSum = sum.bind(null, 2);
This will always bind 2 as the first argument in the sum() function. Now anytime you call that boundSum() function, it will only take one argument, as the 2 is already bound.
boundSum(3); // <-- this would return 5
Your example is using a similar principle. Because you are calling isInSet.bind(null, theSet) it is always binding theSet to the first parameter passed in the isInSet function. However, it is still missing the second parameter. The reason why it works is because you are putting that inside of an ancestry.filter() function. filter() essentially loops over an array and passes each element to the function inside of it (check the docs). So therefore, each element in the ancestry array is getting passed to that bound function, which makes it the second parameter of isInSet().
Read the text from the book a few times and compare the unbound and the bound version.
Calling .bind() on a function, return a new function, with some of the arguments already filled in. The isInSet function, expects two parameters: the set to filter, and a person having a name.
The .filter() method of an array, expects one parameter, namely the function to which each element of the array has to be sent to.
So when you look to the unbound version, you see that the filter function used, just returns isInSet(theSet, person).
So to make the two compatible, we .bind() to create a new function with only one parameter left (namely 'person'), that is bound to theSet. So every time this new function returned by bind gets called, it will use theSet as it's first parameter and will expect only one parameter, 'person'.
Here, person, the second parameter of the original isInSet function we didn't bind, is used as the first and only parameter of the bound function.
So we have exactly what we need after using the bind. A function that will take a 'person' as a parameters and will always look inside the same array (theSet).
If you read the docs for .bind(), you see that it accepts a variable list of arguments. The first argument is the 'this' argument. So if you have a function that uses 'this' inside it and you want to bind it to eg. an object, you can use the 1st parameter. Eg. myFunc.bind( objectToCallUpon, firstArg, secondArg );
Since we don't actually use the 'this' argument in the isInSet() function, we just pass 'null' as the 'this' value.
All the other parameters used are the arguments of isInSet you want to make 'fixed'. Since we want the first parameter to always be theSet, we bind that value.
If the isInSet function would accept two parameters, you would use:
isInSet.bind( null, theSet, secondParameter );
The following piece of code (from msdn) is a simple implementation of the 'bind' function:
/* Approximation of `Function.prototype.bind` from ES5 (without error checking) */
Function.prototype.bind = function(thisArg) {
var fn = this, args = *Array.prototype.slice.call(arguments, 1)*;
return function() {
return fn.apply(thisArg, args.concat(*Array.prototype.slice.call(arguments, 0)*));
};
};
Can anyone explain the first call to Array.prototype.slice.call ? I understand that arguments is not an array and one needs to turn it into an array before using slice and concat. I don't understand the first call - aren't we losing the first element when calling
Array.prototype.slice.call(arguments, 1)?
You are correct.
The zeroth element of arguments is thisArg, which is why it is getting removed.
According to the docs about bind, the first argument (arguments[0]) is the custom this value to be used as the value of this within the the function returned by bind (the "bound function").
What follows (arguments[1] - arguments[n]) are arguments that are to be prepended when calling the bound function, in addition to the arguments that are provided to when called.
What the first Array.prototype.slice.call does is to slice the arguments passed to bind call and get the arguments to be prepended starting from the second argument passed, leaving behind the first argument which would be our this.
For example
var newFN = someFunction.bind(myNewThis,foo,bar,baz);
The first Array.prototype.slice.call takes foo, bar and baz.
In the returned function, foo, bar and baz get prepended to the arguments provided when calling the bound function:
//fn - original function
//args - extracted arguments foo, bar and baz
//thisArg - the provided `this` value, myNewThis
//this code basically:
// - calls the original function (fn)
// - provides a custom `this` value (thisArg)
// - provides arguments that comprise the extracted arguments + the passed arguments
fn.apply(thisArg, args.concat(Array.prototype.slice.call(arguments, 0)));
So when you use the new "bound" function, you get a custom this value, as well as a "preset", prepended arguments list:
newFN('ban','bam'); //arguments === ['foo','bar','baz','ban','bam'];
I am reading the Eloquent JavaScript and I got to Functional programming (chapter 6). I am confused by the following example:
show(Math.min.apply(null, [5, 6]));
function negate(func) {
return function() {
return !func.apply(null, arguments);
};
}
*Note: The show() simply prints out the output to the console on the Eloquent JavaScript website.
I don't get how the negate() function is related to the code within show(). Where is the negate() function called? I don't see that it was used anywhere in that example, or am I wrong?
The code given contains two examples. Every function has an apply method. In the first example, Math.min's apply method is used to call Math.min with the argument list [5,6]. The second example should be viewed in contrast to the preceding example in which negate is defined as
function negate(func) {
return function(x) {
return !func(x);
};
}
In that example, negate(func) returns a new function of one argument that calls func with that single argument, negates the result, and returns it. What happens if func expects more than one argument, though? That's what this example covers.
function negate(func) {
return function() {
return !func.apply(null, arguments);
};
}
In this definition, negate(func) returns a new function of an arbitrary number of arguments that calls func with the list of provided arguments, negates the result, and returns it.
That part of the book was to explain that some functions take multiple parameters, so you must call the func parameter with .apply() instead of just func(x).
The first example used NaN, which accepts one parameter. That's why it worked to use:
return !func(x);
But some functions, like Math.min, accept several parameters. Technically, when using negate, you don't know what function will be passed, and what arguments will be passed. Therefore, you can't hardcode in x being passed to func. Using .apply(), you can pass the original arguments, arguments, to the func call.
Reference:
apply: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply