context to use call and apply in Javascript?
Asked Answered
C

6

75

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 ?

Crunch answered 28/12, 2011 at 17:49 Comment(1)
This read helped me understand the point of thisArg when calling apply() and call() which seems to be the core of your question. You need to understand function invocation primitive in JavascriptBuna
U
83

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.

Unzip answered 28/12, 2011 at 17:52 Comment(6)
just a question about the code snippet provided, why Toy's and Food's prototype gets replaced by a Product object?Vermiculation
Commenting just to bump @Vermiculation question: why do we need to do Toy.prototype = new Product();? I tested this and removing those lines seems to make no difference in the end result.Ap
@Vermiculation & @Ap : It is needed to make Food and Toy inherit from Product. Look at this example: jsfiddle.net/Shawn/xNEYf I removed Toy.prototype = new Product(); but left Food.prototype = new Product(); in, so now Food inherits from Product, but Toy does not. I also added a method to Product's prototype and called it from Food and Toy to make the lack of inheritance more obvious (just open the console and run the code, Food can call the method inherited from Product, but Toy cannot and throws an error).Johny
How would the prototype be used when used with object literals?Lorrin
I guess I just don't understand the purpose for doing this instead of something that seems much easier, such as this.Whale
@Johny If you don't add a Product's prototype and remove Toy.prototype = new Product(); and Food.prototype = new Product(); it works fine then why add those lines in the example.Retouch
G
23

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

Grinder answered 28/12, 2011 at 17:51 Comment(2)
It might refer to the caller obj, if using obj.whatever(); syntax.Ramirez
The statement "But in all other cases - this will refer to the global object unless set explicitly through call" should be corrected to following: "But in all other cases, unless set explicitly through call, this will refer to the global object if using Ecmascript 3 or Ecmascript 5 (or later) in non strict mode. However, in Ecmascript 5 (or later) with strict mode, this is always undefined if not explicitly set and the JS Engine will throw an exception when you access this." Refer to: #9823061Kirman
A
12

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.

Allsopp answered 28/12, 2011 at 18:11 Comment(1)
Thanks, you explain it very well. Finally understand the usage of the first argument.Propitiate
C
4

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.

Coset answered 28/12, 2011 at 18:8 Comment(0)
H
1

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
Havener answered 2/4, 2017 at 12:47 Comment(0)
L
0

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]
Lizbeth answered 10/2, 2017 at 3:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.