I come across this code in jsGarden, and I cannot figure the meaning to chain call and apply together. Both will execute the function with a given context object, why it could be chained?
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Create an unbound version of "method"
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {
// Result: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
It's making a call to call via apply; that is, it's using call to call a function ("method"), and it's using apply to make the call because it's got the arguments in the form of an (almost) array.
So to take it apart:
Function.call
That's a reference to the call() function available on all Function instances, inherited from the Function prototype.
Function.call.apply
That's a reference, via the reference to the call function, to apply. Because apply is referenced via the call object, when the call to apply is made the this value will be a reference to the call function.
Function.call.apply(Foo.prototype.method, arguments);
So we're invoking the call function via apply, and passing Foo.prototype.method to be the this value, and the arguments to "Foo.mmethod" as the arguments.
I think it's basically the same effect as this:
Foo.method = function() {
var obj = arguments[0], args = [].slice.call(arguments, 1);
Foo.prototype.method.apply(obj, args);
}
but I'll have to try it to make sure. edit Yes that seems to be it. So I can summarize the point of that trick as being a way to invoke apply() when the desired this value is the first element of the array holding the parameters. In other words, usually when you call apply() you've got the desired this object reference, and you've got the parameters (in an array). Here, however, since the idea is that you pass in the desired this as a parameter, then it needs to be separated out in order for a call to apply to be made. Personally I would do it as in my "translation" because it's a little less mind-bending (to me), but I suppose one could get used to it. Not a common situation, in my experience.
I think the code should be like this:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
Foo.method = function() {
//Notice this line:
Function.apply.call(Foo.prototype.method, this, arguments);
};
then
Foo.method(1,2,3) => function Foo() {} 1 2 3
Other examples:
Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2]) => [[1, 2]]
apply does take an array as the second argument, call takes single parameters.
// lets take call,
var callfn = Function.prototype.call;
// an ordinary function from elsewhere
var method = Foo.prototype.method;
// and apply the arguments object on it:
callfn.apply(method, arguments);
So, the first arguments item will be the this value of the method, and the subsequent will fill the single parameters.
The result is a static function method on the Foo constructor, that takes a Foo instance (or something similiar) as the first argument and applies the prototype method on it. A possible usecase were to define a Object.hasOwnProperty function, which is normally only available as Object.prototype.hasOwnProperty.
Ultimately, it makes the invocation of the method one "prototype" and one "call" shorter if you need to apply it on objects that a) don't inherit it or b) overwrite it.
Person.prototype.fullname = function(joiner, options) {
options = options || { order: "western" };
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};
// Create an unbound version of "fullname", usable on any object with 'first'
// and 'last' properties passed as the first argument. This wrapper will
// not need to change if fullname changes in number or order of arguments.
Person.fullname = function() {
// Result: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};
The Code from Javascript Garden.
Notice that it state the Function.call.apply(Person.prototype.fullname, arguments);
will become this:
Person.prototype.fullname.call(this, joiner, ..., argN);
It means the apply() function will be excuated first, then the call() function will be execuated.
Pattern: The right most call() / apply() will get execuated first
So right most apply() will get executed first
The context of the apply() becomes the caller of the call() function, so now Person.prototype,fullname.call()
apply()can only take one single array of parameters, so apply() provides arguments to the call() function, so now Person.prototype,fullname.call(arguments)
Examples from #foxiris
1st One:
Function.apply.call(Array,this,[1,2])
The right most call() will get execuated first
The context of call() becomes the caller of the apply() ,so now Array.apply()
The call() can accept multiple arugments, so it can provide this and [1, 2] to apply(), so now Array.apply(this, [1, 2]);, which will output [1, 2]
2nd One:
Function.call.apply(Array,this,[1,2])
The right most apply() will get execuated first
The context of apply() becomes the caller of the call() ,so nowArray.call()
The apply() can only take one single array parameter, so it can only provide this to call(), so now Array.call(this);, output is [].
3rd One:
Function.call.call(Array,this,[1,2])
The right most call() will get execuated first
The context of call()(right most one) becomes the caller of call()(the second to the right), so now Array.call()
The call() can take multiple parameters, so it can provide this and [1, 2] to another call(), so now Array.call(this, [1, 2]);, output is [[1, 2]].
Related
How come we do not have to pass an argument to function b
in the code below? Is it just because we are using map method of type Array? Or is there anywhere else that we can use a function just like this in
JavaScript?
Can someone give a very clean and through explanation?
Code:
/* we have an array a*/
const a = ['a', 'b', 'c'];
/*we define a function called b to process a single element*/
const b = function(x){do something here};
/*I noticed that if we want to use function b to take care with the
elements in array a. we just need to do the following.*/
a.map(b);
Functions are first class citizens in Javascript, which is just a fancy way of saying they can be passed around as variables and arguments.
What you are doing when you call
a.map(b);
Is essentially calling
[
b('a'),
b('b'),
b('c')
]
The array function map just calls the given function (in your case b), with each argument in the array, and puts the output in a new array. So there are arguments being passed to b, it's just that map is doing it behind the scenes for you.
As for your other questions, there are plenty of cases where you'll pass a function as an argument without calling it first. Another common function is the Array object's reduce.
const out = a.reduce(function (accumulator, val) {
return accumulator + ' - ' + val;
}
// out: 'a - b - c'
Also a lot of functions take callbacks, that are called when some kind of asynchronous task is completed. For instance. setTimeout, will call a given function after the elapsed time.
setTimeout(function (){
console.log("Hello World!");
}, 1000
);
// Will print "Hello World!" to console after waiting 1 second (1000 milliseconds).
And you can easily write your function to take another function as an argument too! Just call the function you've passed in as you would any other function.
// A really basic example
// More or less the same as [0, 1, 2].map(...)
function callThreeTimes(f) {
return [
f(0),
f(1),
f(2)
]
}
// My function here returns the square of a given value
function square(val) { return val * val }
const out = callThreeTimes(square);
// out: [0, 1, 4]
You don't pass arguments to b because you're not calling it. You're passing the function itself as a value.
The use of map here is irrelevant; you can see what's happening directly:
const a = function(x) { alert(`called with ${x}`); };
// The function is NOT called here; it's just being assigned,
// like any other kind of value. This causes "b" to become
// another name for "a".
// This is NOT the same as a(), which would call the function
// with undefined as the argument.
const b = a;
// Now we call it, and the alert happens here
b(5);
Passing a function to another function works the same way, since it's just another form of assignment.
This is useful because you can tell other code how to do something even if you yourself don't know what the arguments are. In the particular case of map, it loops over the array for you and calls the function once for each element. You don't want to be calling the function you pass to map, because the entire purpose of map is to call the function for you.
map accepts function as a parameter and executes provided function for every element of an array.
Here you are passing function b as a parameter to map, hence map executes function b for every elements of array a.
So you do not need to pass arguments to function b here, map will take care of this.
You probably heard that functions are first class citizens in javascript.
If you look at the docs from MDN map you will notice that the map function accepts a callback with up to 3 arguments first one being currentValue
So let's break it down. A very explicit example of doing a map over the array above would be this one
a.map(function(currentValue, index, array){
// here you can access the 3 parameters from the function declaration
});
This function is called on each iteration of the array. Since functions are very flexible in javascript, you could only declare 1 parameter or even none if you want to.
a.map(function(currentValue){
// we need only the current value
});
Every function in JavaScript is a Function object. Source here
This means that every function is just a reference in the memory, meaning it can be specified either directly as an anonymous function (which is our case above), or declared before like this
function b(currentValue){
// this will be called on each item in the array
};
a.map(b)
This piece of code iterates over each element in the array and calls the reference we passed it (function b). It actually calls it with all the 3 parameters from the documentation.
[
b('a',0,a),
b('b',1,a),
b('c',1,a)
]
But since our function b only declared one, we can access the value only.
The other arguments are stored in the so-called Arguments object
Take from here Every function in JavaScript is a Function object which makes every function a reference to a certain memory location which in the end leaves us with a lot of flexibility of passing the function as a parameter however we want to (explicit via an anonymous function, or implicit via a function declaration (reference) )
how come we do not have to pass argument to function b here?
Simply because as per spec, map calls the b with 3 implicitly.
callbackfn is called with three arguments: the value of the element,
the index of the element, and the object being traversed
For each element in the array, callback function is invoked with these three arguments
value of the element (a, b and c in your case)
index of the element
b itself (object being traversed).
Why there are no parenthesis?
When you are passing a function as an argument to the sort method it doesnt have parentheses after the function name. This is because the function is not supposed to be called right then and there but rather the map method to have a reference to this function so that it can call it as needed while it's trying to map the array.
Why it does not take any arguments?
Now we know that map will be calling this callback function accordingly, so when map calls it it implicitly passes the arguments to it while calling it.
For example if this would be callback of sort then the argument passed will be current element and next element. If this is a callback for map then the arguments will be current value, index, array.
In JavaScript, functions are just another type of object.
Calling a function without arguments is done as follows. This will always execute the function and return the function's return value.
var returnValue = b();
Removing the parenthesis will instead treat the function itself as a variable, that can be passed around in other variables, arguments etc.
var myFunction = b;
At any point such adding parenthesis to the "function variable" will execute the function it refers to and return the return value.
var returnValue = myFunction();
var sameReturnValue = b();
So map() accepts one argument, which is of type function (no parenthesis). It will then call this function (parenthesis) for each element in the array.
Bellow you will find how to use the map function:
first Methode
incrementByOne = function (element) {
return element + 1;
}
myArray = [1,2,3,4];
myArray.map(incrementByOne); // returns [2,3,4,5]
Seconde methode
myArray = [0,1,2,3];
myArray.map(function (element) {
return element + 1;
}); // returns [1,2,3,4]
Third Methode
myArray = [1,2,3,4];
myArray.map(element => {
return element + 1;
});
NOT I DON'T KNOW HOW OTHERS WORDED THIS QUESTION IF THIS IS A DUPLICATE
So i have been starting to leard oop in js. It is my first language. Out of the 3 elements, i have decided to start learning inheritance. I seem to have grasp objects inheriting from other objects, though i have not applied it to any coding challenges yet.
But the problem: I tried learning constructors inheriting from constructors, and i learned you need object.call().
According to Mozila.developer, the this is a provided argument. I am assuming that i do not have to worry about it.
But I am confused on what the arguments do after the this.
From mozilla:
"Parameters
thisArg
The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object and primitive values will be converted to objects.
arg1, arg2, ...
Arguments for the object.
Return value
The result of calling the function with the specified this value and arguments."
Example:
function a(r){
this.r = r;
}
function b(r){
a.call(this, .....)
}
b.prototype = object.create(a.prototype);
But I am confused on what the arguments do after the this.
The arguments after the thisArg are passed one-by-one to the called function. In your example:
function A(r_a){
this.r = r_a;
}
function B(r_b){
A.call(this, r_b)
}
var b = new B(1)
The value 1 is passed to B where it is available as r_b, which is passed via the call method into A where it is available as the r_a parameter and ends up in the b.r property.
You can pass arbitrarily many arguments this way.
.call() invokes the function that you call it on. The first parameter passed to it becomes this inside that function. the rest are passed as the functions parameters. Simple example:
function callMe(param1, param2) {
console.log(param1 + this.separator + param2);
}
callMe.call({ separator: ' ' }, 'Hello', 'world!'
So the object { separator: ' ' } is set to this, 'Hello' and 'world!' are passed to callMe as param1 and param2
results in:
"Hello World!"
So in your example, you probably want to do:
function b(r){
a.call(this, r)
}
which would just invoke the a() function and forward the parameter r to it.
The reason you can't just do:
function b(r) {
a(r);
}
is that the this context inside a() would be wrong. Using .call() here preserves the this context when invoking a(), so b() and a() both execute with the same this context.
I'm reading the MDN Article on slice in JavaScript. I understand everything except the 2nd example in the section titled Array-Like Objects.
It says we can simplify the first example by making slice our own function as so:
var unboundSlice = Array.prototype.slice;
var slice = Function.prototype.call.bind(unboundSlice);
function list() {
return slice(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
What I don't understand is how call can come right after prototype on the second line.
I usually see it in the form of Array.prototype.slice.call(arguments) or something of that sort.
I don't understand the flow of the first two lines and how they generate this working slice function.
tl;dr:
var slice = Function.prototype.call.bind(unboundSlice);
is a short way of writing:
var slice = function(value, start, end) {
return unboundSlice.call(value, start, end);
};
Let's think about this line for second:
Array.prototype.slice.call(arguments)
.slice is an array method to extract a subset of the array. It operates on the value of this. .call is a method every function has, it lets you set the this value for a function execution. So, the above line lets us execute slice as a method of arguments, without having to mutate arguments itself. We could have done
arguments.slice = Array.prototype.slice;
arguments.slice();
but that is not as clean.
Now looking at
Function.prototype.call.bind(unboundSlice);
As said, .call is a method that every function has. It also operates on this, which is expected to be a function. It calls this and sets the this value of that function to the first argument. You could think of call as being similar to
function call(thisValue, arg1, arg2, ...) {
return this.apply(thisValue, [arg1, arg2, ...]);
}
Note how it calls this as a function.
.bind is also a method every function has. It returns a new function which has its this value fixed to the first argument you pass in.
Let's consider what the resulting function of call.bind(unboundSlice) would look like:
function boundCall(thisValue, arg1, arg2, ...) {
return unboundSlice.apply(thisValue, [arg1, arg2, ...]);
}
We simply replaced this with unboundSlice. boundCall will now always call unboundSlice.
The MDN article for Function.prototype.call() helped me wrap my head around this.
The most simplistic way I can answer:
In javascript, a Function has a method called call. A function is an
object, and all objects inherit methods and properties from their
prototype.
So your example of Array.prototype.slice.call(arguments) shows you calling the call method on the slice function.
The second line in the code that you are confused about: var slice = Function.prototype.call.bind(unboundSlice); shows the call method belonging to the Function prototype.
Checkout JavaScript Prototypes if you are still confused.
1 Functions are objects.
2 "Every JavaScript object has a prototype."
3 "The prototype is also an object."
4 "All JavaScript objects inherit their properties and methods from their prototype."
In other words, back to the most simplistic way to answer this: In javascript, a Function has a method called call.
As for understanding what bind does, the that = this vs .bind example in this article helps make sense of what is going on.
If that was confusing, then make sure you understand context and scope
slice is a property of Array.prototype, and it expects its this object to be Array-like. You can use it on Array-like objects (that have a length property and have properties that you can index) that don't have their own slice function like so:
Array.prototype.slice.call(arraylikething);
That's a lot of typing, so we can make a function to do the same thing:
var slice = function(arraylikething){
return Array.prototype.slice.call(arraylikething);
};
JavaScript provides Function.prototype.bind to bind functions to a specified this object. So we can accomplish the same thing a bit more easily:
var slice = Function.prototype.call.bind(Array.prototype.slice);
bind creates a new function that returns the result of call with its this object set to Array.prototype.slice, the same as what we did manually above, and equivalent to your code.
The answer from Chris Dillinger is correct and informative. But here's another way to think about it. You're being asked, in essence, to define
Function.prototype.call.bind(Array.prototype.slice)
Which you can look at this way:
fn.bind(context)
==> function(...args) {return context.fn(...args);}
// 1. definition of `bind` (oversimplified, but enough for this case)
fn.bind(unboundSlice)
==> function(...args) {return unboundSlice.fn(...args);}
// 2. substitute `unboundSlice` for `context`
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[Function.prototype.call](...args);}
// 3. substitute `Function.prototype.call` for `fn`.
Function.prototype.call.bind(unboundSlice)
==> function(...args) {return unboundSlice[.call(...args);}
// 4. walk the prototype chain
Function.prototype.call.bind(Array.prototype.slice)
==> function(...args) {return Array.prototype.slice.call(...args);}
// 5. substitue `Array.prototype.slice` for `unboundSlice`
The only step that's even slightly tricky is step 4, where you have to realize that all functions inherit the call method from their prototype chain, so invoking call on them is merely an alternative means of invoking the functions themselves.
In the first line, Array.prototype.slice (which is a method) is simply referenced via unboundSlice. You're essentially 'extracting' the slice method from Array.prototype.
In the second line, the same thing happens for Function.prototype.call, which is also a method of ALL functions. (it's defined in Function.prototype, and inherited by all functions).
Next, by using .bind(unboundSlice) the Call function's this value is bound to the reference to Array.prototype.slice, which essentially results in the same thing as Array.prototype.slice.call(), where call also has its this bound to slice, because of it being a method of it, AND because it's being called like that.
Lastly, the bound call method is referenced via var slice;
The general idea here is that you're able to use the functionality of an array method (slice) in another context (the global scope).
So now, instead of calling call when it was already a method of slice, you're binding slice to be the this value of call in order to achieve the same behaviour.
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'];
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,
**args.concat(Array.prototype.slice.call(arguments))**);
};
};
This function is in Prototype. Does it equal to:
Function.prototype.bind = function(){
var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
return function(){
return fn.apply(object,**args**);
};
};
In my opinion, args.concat(Array.prototype.slice.call(arguments)) == args, since the anonymous
function haven't any arguments. What is the matter?
No, they aren't the same.
Tthe purpose of concatenating the arguments is to provide a way of partially apply (or curry) the function, pre-filling arguments when bind is used and being able to add more later when the function that bind returns is used, for example:
var obj = {
fx: function() {
alert(Array.prototype.join.call(arguments, ', '));
}
};
var fx2 = obj.fx.bind(obj, 1, 2, 3);
fx2(4, 5); // Alerts "1, 2, 3, 4, 5"
As you can see in the last two lines of code, when I declare fx2, I'm passing obj as the first argument (this will ensure the context, used as the object variable on the bind implementation), then I pass the values 1,2 and 3.
Those values are stored in the args variable of the outer closure of bind, then as you see in the bind implementation, another function is returned.
That function returned in my example is fx2 after the assignment, in the last line you see I call that function, passing two additionally arguments.
Finally the returned function will call obj.fx with the two argument lists, the arguments we pre-filled when calling bind (1,2,3) and the arguments when the function actually executed (4,5).
That is why makes sense concatenating the two argument objects.
the anonymous function haven't any arguments
The anonymous function can actually have arguments (as can the bind method itself, which also doesn't declare any arguments).
Type-checking in JavaScript is non-existent: you can pass fewer arguments into a function than are declared in the function(...) signature (in which case the arguments that aren't passed get received as undefined), and you can pass more than declared, in which case the only way to read them is through the arguments array, which always contains exactly how many arguments were passed in, regardless of what's in the function signature.
It's generally considered polite to put a comment in the signature (function(x, /* y, ... */)) to indicate that more arguments will be read using the arguments array.