Apply, call, bind in JavaScript

Source: Internet
Author: User

Apply, call

In JavaScript, call and apply are meant to change the context in which a function is run, in other words, to change the direction of this within the function body.

A major feature of JavaScript is the notion that a function has a "context of definition" and a "runtime context" and a "context can be changed."

First, a chestnut:

1234567891011 function fruits() {} fruits.prototype = {    color: "red",    say: function() {        console.log("My color is " + this.color);    }} var apple = new fruits;apple.say();    //My color is red

But if we have an object banana= {color: "Yellow"}, we don't want to redefine it say method, then we can use call or apply with Apple's say method:

12345 banana = {    color: "yellow"}apple.say.call(banana);     //My color is yellowapple.say.apply(banana);    //My color is yellow

So, you can see that call and apply are to change this dynamically, when an object does not have a method (this pest banana no say method), but the others have (this pest Apple has say method), We can use call or apply to manipulate other object methods.

The difference between apply and call

For both apply and call, the function is exactly the same, except that the parameters are accepted in a different way. For example, there is a function defined as follows:

123 varfunc = function(arg1, arg2) {    };

You can invoke the following method:

12 func.call(this, arg1, arg2);func.apply(this, [arg1, arg2])

Where this is the context you want to specify, he can be any JavaScript object (everything in JavaScript), call needs to pass parameters in order, and apply is to put the parameters in the array.

In JavaScript, the number of arguments for a function is not fixed, so if you want to apply the condition, call is used when your parameters are clearly known.

Use apply when unsure, and then pass in the parameter push into the array. When the number of arguments is indeterminate, the function can also traverse all the arguments by arguments the array.

To consolidate your memory, here are some common uses:

1. Append between arrays

1234 vararray1 = [12 , "foo" , {name "Joe"} , -2458]; var array2 = ["Doe", 555 , 100]; Array.prototype.push.apply(array1, array2); /* array1 值为  [12 , "foo" , {name "Joe"} , -2458 , "Doe" , 555 , 100] */

2. Get the maximum and minimum values in the array

123 varnumbers = [5, 458 , 120 , -215 ]; varmaxInNumbers = Math.max.apply(Math, numbers),   //458    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

Number itself does not have the Max method, but with Math, we can use call or apply its methods.

3. Verify that it is an array (provided the ToString () method has not been rewritten)

123 functionisArray(obj){     returnObject.prototype.toString.call(obj) === ‘[object Array]‘;}

4. Class (pseudo) array using array method

1 vardomNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));

There is an object structure called a pseudo-array in JavaScript. In particular, arguments objects, as well as calls to getElementsByTagName, document.childnodes and so on, return nodelist objects that are pseudo-arrays. You cannot apply the push, pop, and other methods under the array.

But we can convert the object with the length property to the real array by Array.prototype.slice.call, so that domnodes can apply all the methods under the array.

In-depth understanding of applying apply, call

Below to borrow an interview question, to go deeper to understand the next apply and call.

Define a log method that allows it to proxy the Console.log method, and the common workaround is to:

12345 functionlog(msg) {  console.log(msg);}log(1);    //1log(1,2);    //1

The above method can solve the most basic requirements, but when the number of incoming parameters is not deterministic, the above method is invalid, this time you can consider using apply or call, notice here how many parameters are indeterminate, so using apply is the best, the method is as follows:

12345 functionlog(){  console.log.apply(console, arguments);};log(1);    //1log(1,2);    //1 2

The next requirement is to add a "(app)" prefix to each log message, such as:

1 log("hello world");    //(app)hello world

What should be more elegant? This time you need to think that the arguments parameter is a pseudo-array, converted to a standard array by Array.prototype.slice.call, and then using the array method Unshift, like this:

123456 functionlog(){  var args = Array.prototype.slice.call(arguments);  args.unshift(‘(app)‘);   console.log.apply(console, args);};
Bind

Finish the Apply and call, and then say bind. The bind () method is similar to apply and call and can also change the direction of this in the function body.

The MDN explanation is that the bind () method creates a new function called a binding function that, when called, binds the binding function to the first parameter of the bind () method as it is created when it is passed into bind () The second and subsequent parameters of the method plus the arguments of the binding function itself are invoked in order as parameters of the original function to invoke the original function.

Take a look directly at how to use it, in common monomer patterns, we usually use _this, that, self, and so on to save this, so that we can continue to reference it after changing the context. Like this:

12345678910 var foo = {    bar : 1,    eventBind: function(){        var _this = this;        $(‘.someClass‘).on(‘click‘,function(event) {            /* Act on the event */            console.log(_this.bar);     //1        });    }}

Due to Javascript-specific mechanisms, the context is transitioning to $ ('. SomeClass ') in Eventbind:function () {}. On (' click ', Function (event) {}) changed, the above using variables to save This is all useful and there is nothing wrong with it. Of course, using bind () can solve this problem more gracefully:

123456789 var foo = {    bar : 1,    eventBind: function(){        $(‘.someClass‘).on(‘click‘,function(event) {            /* Act on the event */            console.log(this.bar);      //1        }.bind(this));    }}

In the above code, bind () creates a function that, when the Click event is bound to be called, its this keyword is set to the value passed in (this refers to the parameter passed in when bind () is called). So here we pass in the desired context this (actually foo), into the bind () function. Then, when the callback function is executed, this points to the  foo  object. One more simple chestnut:

123456789 var bar = function () { console.log ( This .x); } var foo = { x:3 } Bar (); //undefined var func = Bar.bind (foo); func (); //3

Here we create a new function func, when it is executed by using bind () to create a binding function, it will be set to Foo instead of the global scope as we call Bar ().

The interesting question is, if you have a continuous bind () two times, or a continuous bind () three times, what is the output value? Like this:

1234567891011121314151617 var bar = function(){    console.log(this.x);}var foo = {    x:3}var sed = {    x:4}var func = bar.bind(foo).bind(sed);func(); //? var fiv = {    x:5}var func = bar.bind(foo).bind(sed).bind(fiv);func(); //?

The answer is that the two will still output 3, not the expected 4 and 5. The reason is that in JavaScript, multiple bind () is not valid. For a deeper reason, the implementation of BIND () is equivalent to using a function to wrap a call/apply inside, and the second bind () is equivalent to wrapping the first bind (), so the second bind is not valid.

Apply, call, bind comparison

So what are the similarities and differences between apply, call, and bind? When to use apply, call, and when to use bind. Simple one of the chestnuts:

12345678910111213 var obj = {    x: 81,}; var foo = {    getX: function() {        return this.x;    }} console.log(foo.getX.bind(obj)());  //81console.log(foo.getX.call(obj));    //81console.log(foo.getX.apply(obj));   //81

All three outputs are 81, but note that with the bind () method, he has more pairs of parentheses behind him.

That is, the difference is that the bind () method is used when you want to change the context and not execute immediately, but rather when the callback executes. The Apply/call executes the function immediately.

Let's summarize:

    • Apply, call, and bind are all pointers to the This object that is used to change the function;
    • Apply, call, bind the first parameter is the object that this is to point to, that is, the context you want to specify;
    • Apply, call, bind three can use the following parameters to pass the parameter;
    • Bind is to return the corresponding function, which is convenient to call later; apply, call is called immediately.

Apply, call, bind in JavaScript

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.