When and why to use Call and Apply? - javascript

Firstly I came to know the difference between apply() and call().
function theFunction(name, profession) {
alert("My name is " + name + " and I am a " + profession + ".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]); // This call be called theFunction("Susan", "school teacher");, why use apply
theFunction.call(undefined, "Claude", "mathematician"); // This call be called theFunction("Claude", "mathematician");, why use call
From the above code, all the 3 function call displays the alert message.
What are the advantages/disadvantages of using apply and call, over normal function call, and when is it appropriate to use apply/call, please clarify me.
One more thing, what if the function is a prototype based function:
Function.prototype.theFunction = function(name, profession) {
alert("My name is " + name + " and I am a " + profession + ".");
}
Then how to call this function bu using apply or call. I tried this way:
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
but resulted in error.
"ReferenceError: theFunction is not defined"

As you have said it seems that you already know what these to functions apply() and call() actually do, but in terms of their uses, I'd say they are used mostly when you want to provide your function with a specific object of your own, as its this value in its context.
One of the most popular use of these two is to handle array-like objects like arguments objects in the function:
function(){
//let's say you want to remove the first parameter from the arguments object
//you can make sure that
console.log(arguments instanceof Array);//false
//as you see arguments is not an actual array object but it is something similar
//and you want slice out its value
var myparams = Array.prototype.slice.call(arguments, 1);
//here you have myparams without your first argument
console.log(arguments);
}
Let's go with another example. Say we have an independent function like:
function getName(){
console.log(this.name);
}
Now you can use it for any kind of JavaScript object that has a name attribute:
var myInfo = {
name: 'SAM'
};
now if you do:
getName.call(myInfo);
what it does is printing out the name attribute or you can try it on the function itself:
getName.call(getName);
which would print out the function's name ("getName") in the console.
But similar to my first example, it is usually used when you want to use functions that are not in the object's prototype chain. The other example of that could be:
//let's say you have an array
var myArray = [1 , 2];
//now if you use its toString function
console.log(myArray.toString());//output: "1,2"
//But you can use the Object toString funcion
//which is mostly useful for type checking
console.log(Object.prototype.toString.call(myArray));//output: "[object Array]"

This post gives a very detailed explanation of call() and apply().
TLDR;
Both call() and apply() are methods we can use to assign the this
pointer for the duration of a method invocation
The apply() method is identical to call(), except apply() requires an
array as the second parameter. The array represents the arguments for
the target method.

The main difference is that apply lets you invoke the function with arguments as an array; call requires the parameters be listed explicitly.
It Will Give You More Explaination
POST

Related

Passing argument from one function to another

I'm wondering if this way of passing an argument from one function to another (let's say from f1 to f2):
f1 = function(arg){
f2(arg);
}
f2 = function(arg){
//doing sth with passed argument
}
Is wrong? Or is it better/safer to always use the .apply() method, even if we're not passing an array?
To clarify- argument is passed only to f1, and only from f1 f2 is called.
No, it's not wrong.
Passing parameters through functions is one of the fundamental aspects of JavaScript as a language. It helps you take a complex application and break it down into manageable chunks for both clarity and maintainability.
.apply is useful when you want to call a function with a specific scope ( that's why the first parameter is this ) and it takes an array or array-like secondary parameter for arguments to be used within the function. The fact that it's an array/array-like makes no difference at all to you as a programmer or to the function that you're calling. There's nothing special about it, it's just the format that apply expects.
Nothing wrong about that at all. This happens all the time.
The only reason you should use apply() is if you need what it does, like changing the context (value of this) or passing an array as individual arguments. You aren't doing anything like that here, so there is absolutely no reason to make more complicated.
When you declare an argument in JavaScript it's treated just like a variable, and you can use it like any other variable: reassign values, pass it to another function, etc. .apply(this, arguments) is also possible, but it's not necessary unless you need to set the this of the called function or to pass an arbitrary number of arguments.
The apply() method takes arguments as an array.
The apply() method is very handy if you want to use an array instead of an argument list.
<!DOCTYPE html>
<html>
<body>
<h2>JavaScript Functions</h2>
<p>In this example the fullName method of person is <b>applied</b> on person1:</p>
<p id="demo"></p>
<script>
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"John",
lastName: "Doe",
}
var x = person.fullName.apply(person1, ["Oslo", "Norway"]);
document.getElementById("demo").innerHTML = x;
</script>
</body>
</html>
While if you use two function and call One in another:
function function_one() { function_two(); }
function function_two() {
//enter code here
}
Function parameters are the names listed in the function definition.
Function arguments are the real values passed to (and received by) the function.
Parameter Rules
JavaScript function definitions do not specify data types for parameters.
JavaScript functions do not perform type checking on the passed arguments.
JavaScript functions do not check the number of arguments received.
Parameter Defaults
If a function is called with missing arguments(less than declared), the missing values are set to: undefined
more information JavaScript you can read this link
https://developer.mozilla.org/it/docs/Web/JavaScript

Function.prototype.bind.apply() doesn't work as expected

I've a function myfunc and want to bind it to a specific this argument and other arguments to bind as a single array, not parameters list (cause I get the parameters list as an argument of function, where this code is executed).
For that purpose I use apply on bind as follows:
var myfunc = function(arg1, arg2){
alert("this = " + this + ", arg1 = " + arg1 + ", arg2 = " + arg2);
}
var bindedMyfunc = myfunc.bind.apply("mythis", ["param1", "param2"]);
bindedMufunc();
This results in Uncaught TypeError: Bind must be called on a function.
What am I doing wrong? Could you explain in detail, what's going onwhen I run this code, cause reality seems to contradict my opinion on that?
Summary of answers:
Seems that bind itself has its own this argument, which is the function, it is called on. E.g. when you say myfunc.bind(args), bind's this is myfunc.
By calling apply on bind I've mistakingly assigned bind's this to "mythis", which is not a function and bind can't be called on it.
So, the solution is to use
myfunc.bind.apply(myfunc, ["mythis"].concat(["param1", "param2"]))
Also, if you want to call the binded myfunc right off, you could say:
myfunc.apply.bind(myfunc)("mythis", ["param1", "param2"])
but this doesn't suffice my case, cause I need to pass the binded function as an argument to addEventListener.
Thanks for your help, guys!
You should use the function as the first parameter to the apply method. The use of myfunc.bind doesn't associate the function with the call, it has the effect of Function.prototype.bind, and you can just as well use that.
The first parameter for the bind method (thisArg) should be the first item in the array.
var bindedMyfunc = Function.prototype.bind.apply(myfunc, ["mythis", "param1", "param2"]);
Seems that bind itself has its own this argument, which is the function, it is called on. E.g. when you say myfunc.bind(args), bind's this is myfunc.
Exactly. If you want to apply bind, then you have to apply it to the function (the first parameter), and pass the bind arguments (including the intended this value) as an array (the second paramter):
(Function.prototype.bind).apply(myfunc, ["mythis", "param1", "param2"])
// which is equivalent to
myfunc.bind("mythis", "param1", "param2")
(…args) => myfunc.call("mythis", "param1", "param2", …args) // ES6 syntax
However, there is another way to solve your problem: bind apply to the function, and partially apply the proposed apply arguments:
(Function.prototype.apply).bind(myfunc, "mythis", ["param1", "param2"])
// which is equivalent to
(…args) => myfunc.apply("mythis", ["param1", "param2"], …args) // ES6 syntax
Maybe you want to bind apply rather than applying bind?
var bindedMyfunc = Function.prototype.apply.bind(myfunc);
bindedMyfunc('obj', [1, 2]); // this = obj, arg1 = 1, arg2 = 2
I often use this pattern to make hasOwnProperty checks shorter without being shadowable;
var has = Function.prototype.call.bind(Object.hasOwnProperty);
has({foo:1}, 'foo'); // true
has({foo:1}, 'bar'); // false

How is "This" assigned when calling an anonymous function using "Call"?

From MDN:
var animals = [
{species: 'Lion', name: 'King'},
{species: 'Whale', name: 'Fail'}
];
for (var i = 0; i < animals.length; i++) {
(function (i) {
this.print = function () {
console.log('#' + i + ' ' + this.species + ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
In the example above, how is "this" being used in the anonymous function inside the "animals" loop? I am curious as to why "this" is referencing the animal object instead of the window.
If I were, for example, to remove animals[i] from the arguments, then everything is undefined. Does that mean that anonymous functions derive their "identity" from the first parameter they receive or is something else going on?
Thanks in advance!
Isn't this explained in the documentation of function.call() you quote yourself?
fun.call(thisArg[, arg1[, arg2[, ...]]])
Parameters
thisArg The value of this provided for the call to fun. [...]
and later:
Description
You can assign a different this object when calling an existing function.
So you are right, animals[i] is used as this inside a function. You can treat it as implicit, hidden parameter that always has this name.
It's this part:
}).call(animals[i], i);
By calling with .call(), the value for this is specified explicitly.
There are two similar functions available from the Function prototype: .call() and .apply(). They both allow a function (any function, anonymous or not — there's no real difference) to be invoked with some particular value (a reference to an object) as this.
The value of this is always set one way or another when a function is invoked. If the reference to the function is determined by a . or [ ] expression:
something.fn( whatever );
something[ expression ](whatever);
then the value of this is the value of the base object ("something" in the above examples). Mr. Eich calls that the "receiver", which makes sense if you think of function calls like Smalltalk messages.
If you call a function without a base object, then the value of this is either the global object, or null if you're in "strict" mode.
Because you are using call which is defined as:
call(thisScope, args)
So the fact you're passing in animal[i] as thisScope means this == animal[i].

context to use call and apply in Javascript?

Guys can any one explain context to use call and apply methods in Javascript?
Why to use call and apply instead of calling a function directly ?
You use call or apply when you want to pass a different this value to the function. In essence, this means that you want to execute a function as if it were a method of a particular object. The only difference between the two is that call expects parameters separated by commas, while apply expects parameters in an array.
An example from Mozilla's apply page, where constructors are chained:
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0)
throw RangeError('Cannot create product "' + name + '" with a negative price');
return this;
}
function Food(name, price) {
Product.apply(this, arguments);
this.category = 'food';
}
Food.prototype = new Product();
function Toy(name, price) {
Product.apply(this, arguments);
this.category = 'toy';
}
Toy.prototype = new Product();
var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);
What Product.apply(this, arguments) does is the following: The Product constructor is applied as a function within each of the Food and Toy constructors, and each of these object instances are being passed as this. Thus, each of Food and Toy now have this.name and this.category properties.
Only if you use call or apply you can modify the this context inside the function.
Unlike other languages - in JavaScript this does not refer to the current object - rather to the execution context and can be set by the caller.
If you call a function using the new keyword this will correctly refer to the new object (inside the constructor function)..
But in all other cases - this will refer to the global object unless set explicitly through call
You use .call() when you want to cause a function to execute with a different this value. It sets the this value as specified, sets the arguments as specified and then calls the function. The difference between .call() and just executing the function is the value of the this pointer when the function executes. When you execute the function normally, javascript decides what the this pointer will be (usually the global context window unless the function is called as a method on an object). When you use .call(), you specify exactly what you want this to be set to.
You use .apply() when the arguments you want to pass to a function are in an array. .apply() can also cause a function to execute with a specific this value. .apply() is most often used when you have an indeterminate number of arguments that are coming from some other source. It is often used too pass the arguments from one function call to another by using the special local variable arguments which contains an array of arguments that were passed to your current function.
I find the MDN references pages for .call() and .apply() helpful.
If you have experience with jQuery, you will know that most functions take use of the this object. For example, collection.each(function() { ... });
Inside this function, "this" refers to the iterator object. This is one possible usage.
I personally have used .apply() for implementing a queue of requests - I push an array of arguments into the queue, and when the time comes for executing it, I take an element, and pass it as the arguments for a handler function using .apply(), thus making the code cleaner then if having to pass an array of arguments as a first argument. That's another example.
In general, just keep in mind that those ways to call a function exist, and you may one day find them convenient to use for implementing your program.
If you have experience with Object Oriented Programming then call and apply will make sense if you compare it with inheritance and override the properties or method/functions of parent class from child class. Which is similar with call in javascript as following:
function foo () {
this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
console.log(this.helloworld)
}
foo.prototype.main = function () {
this.print()
}
function bar() {
this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
console.log(this.helloworld)
}
var iamfoo = new foo()
iamfoo.main() // prints: hello from foo
iamfoo.main.call(new bar()) // override print and prints: hello from bar
I can't think of any normal situation where setting the thisArg to something different is the purpose of using apply.
The purpose of apply is to pass an array of value to a function that wants those values as arguments.
It has been superseded in all regular everyday usage by the spread operator.
e.g.
// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`
// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2);
// which becomes
arr1 = [...arr2, ...arr1]

JavaScript Binding

thank you if you can help. Source of code http://ejohn.org/apps/learn/#84
1) in line 3 of the program below, where it says return context[name] what does this mean? Im guessing that it means name is bound to the context as a result of the apply function? Is that correct?
2)If my guess in 1 is correct, why does it use the [] brackets? Is that just the syntax. When I look at it, it makes me think array or object?
3) When it says apply(context, arguments) is arguments not the same as name or is arguments both context and name together? to put it another way, in the language of the call bind(Button, "click") is arguments only "click" or is it both button and click?
4) I tried to rewrite line 3 by substituting name for arguments like this
return context[name].apply(context, name);
but it didn`t work anymore, which raises the questions
a)if it is returning name bound to context (i.e. context[name]), why isn`t it sufficient to just have apply(context,name)?
b) if arguments includes both name and context, is the third line of the function essentially
return context[name].apply(context, [context, name]);
c) if my assumption in 4(b) is correct, why would we effectively have to have context passed twice in order to bind name to context? which is to say, I dont understand why line 3 doesnt work if you just write apply(context, name) instead of apply(context,arguments)
function bind(context, name){
return function(){
return context[name].apply(context, arguments);
};
}
var Button = {
click: function(){
this.clicked = true;
}
};
var elem = document.createElement("li");
elem.innerHTML = "Click me!";
elem.onclick = bind(Button, "click");
document.getElementById("results").appendChild(elem);
elem.onclick();
assert( Button.clicked, "The clicked property was correctly set on the object" );
Click me!
It may be helpful to understand the basics of JavaScript objects before diving into the specifics. Any JavaScript property can be accessed with the bracket notation, or the dot notation (if it is a valid identifier). It can be confusing since arrays also use this notation. Say there is an object of cars and their makes,
var cars = { Ford: 2007, Honda: 2010, BMW: 2011 };
Then we can access their keys using the dot notation or the bracket notation
cars.Ford // 2007
cars["Honda"] // 2010
Next, remember that functions are first class citizens in JavaScript. So you could use them as ordinary variables including storing them as object property values, in arrays, etc. Let's replace the years in the previous cars example with actual functions,
var cars = {
Ford: function() { alert("2007"); },
Honda: function() { alert("2010"); },
BMW: function() { alert("2011"); }
};
The keys Ford, Honda, and BMW can still be accessed as in the previous example with the dot or bracket notation, with the only difference that this time a function will be returned instead of the integer year.
cars["BMW"] now returns a function which can be directly invoked as
cars["BMW"](); // or
cars.BMW(); // or
var name = "BMW";
cars[name]();
That's not all. There are still two more ways to execute a function - through apply and call. The difference between apply and call is subtle but you should read up more about them.
Finally, arguments represents an array-like object that contains the arguments passed in to a function. This is best demonstrated by an example,
function whatever() {
console.log(arguments);
}
whatever(1, 2); // [1, 2]
whatever("foo", "bar", 23, [4, 6, 8]); // ["foo", "bar", 23, [4, 6, 8]]
whatever(); // undefined
Without giving any names to the function parameters, we were able to log all the arguments passed to the function. Since it is an array like object, access each argument individually as arguments[0], arguments[1], etc.
And now to answer your questions,
1) in line 3 of the program below, where it says return context[name] what does this mean? Im guessing that it means name is bound to the context as a result of the apply function? Is that correct?
context[name] is similar to the cars['Ford'] example above. It is supposed to give a function which is then invoked by calling apply on it. When that function is called, inside the function this will refer to the object - context.
2) If my guess in 1 is correct, why does it use the [] brackets? Is that just the syntax. When I look at it, it makes me think array or object?
Hopefully this was answered above.
3) When it says apply(context, arguments) is arguments not the same as name or is arguments both context and name together? to put it another way, in the language of the call bind(Button, "click") is arguments only "click" or is it both button and click?
arguments has nothing to do with either context or name. It is simply a list of the arguments/parameters that the function was called with. Hopefully the above description cleared this as well.
4) I tried to rewrite line 3 by substituting name for arguments like this
return context[name].apply(context, name);
but it didn`t work anymore
It didn't work because apply expects the second argument to be an Array, and you passed it a String. Try return context[name].apply(context, [name]); instead.
which raises the questions
a) if it is returning name bound to context (i.e. context[name]), why isn`t it sufficient to just have apply(context,name)?
b) if arguments includes both name and context, is the third line of the function essentially
return context[name].apply(context, [context, name]);
arguments has nothing to do with the context, or name. Hopefully this was cleared up in the above examples.
c) if my assumption in 4(b) is correct, why would we effectively have to have context passed twice in order to bind name to context? which is to say, I dont understand why line 3 doesnt work if you just write apply(context, name) instead of apply(context,arguments)
The above answers already answer this part.
1) context[name] just means the property of the "context" object with that name. In the case of:
bind(Button, "click");
that works out to Button["click"], which is the click() function inside the Button object
2) All objects in Javascript are a collection of properties, which can be accessed by their names. Given the definition:
var Button = {
click: function(){
this.clicked = true;
}
};
both Button.click and Button["click"] would refer to the same thing - the function click() inside the Button object.
3) The arguments keyword refers to an array-like object containing all of the arguments passed to a function. In the example, bind() is returning a newly-created function. The "arguments" referred to in that function are whatever arguments that function gets called with. In this case, it's neither context nor name, it's whatever the onclick mechanism passes to the event handler.
Here's a slightly different way to write the code that sets up the event handler:
var elem = document.createElement("li");
elem.innerHTML = "Click me!";
var boundFunction=bind(Button, "click");
elem.onclick=boundFunction;
document.getElementById("results").appendChild(elem);
Maybe this makes it more clear that when you call bind(), it returns a new function. If you were to call the boundFunction like this:
boundFunction("these", "are", "arguments")
The use of arguments is inside the returned function, so arguments would be ["these", "are", "arguments"] in this case. The arguments that were passed to "bind" are used to construct the function that bind returns, so they're no longer relevant when the bound function gets called.
4) Until you understand the basics of how returning a function from another function works, this'll be pretty confusing. The purpose of apply() is to set the "this" keyword for a particular function invocation. Given the definition of Button, you might expect to be able to do this to set up the event handler:
elem.onclick = Button.click;
This doesn't work correctly, because when the event handling code calls the Button.click function, "this" is set to the global context, rather than to the Button instance. The purpose of the bind() function is to make a function that sets "this" appropriately, then calls the function you originally passed to bind().
I have a half-completed blog entry on this which might be a simpler example:
http://codemines.blogspot.com/2010/01/javascript-by-example-functions-and.html

Categories

Resources