Home > Web Front-end > JS Tutorial > Explain in simple terms how to use apply, call, and bind in Javascript

Explain in simple terms how to use apply, call, and bind in Javascript

伊谢尔伦
Release: 2016-12-01 10:07:19
Original
1452 people have browsed it

Although there are many articles online, most of them are copied and pasted, and are difficult to understand. I hope that through this article, I can clearly improve my understanding of apply, call, and bind, and list some of their wonderful uses to deepen my memory.

Explain in simple terms how to use apply, call, and bind in Javascript

 apply, call

 In JavaScript, call and apply both exist to change the context when a function is running. In other words, they are to change the pointer of this inside the function body.

 A major feature of JavaScript is that functions have the concepts of "definition-time context" and "runtime context" and "context can be changed".

  Let’s start with a chestnut:

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
Copy after login

But if we have an object banana= {color : "yellow"} , and we don’t want to redefine the say method on it, then we can use apple’s say method through call or apply:

banana = {
    color: "yellow"
}
apple.say.call(banana);     //My color is yellow
apple.say.apply(banana);    //My color is yellow
Copy after login

So, it can be seen that call and apply appear to dynamically change this. When an object does not have a certain method (banana in this chestnut does not have a say method), but others do (apple in this chestnut has a say method), we You can use call or apply methods to operate on other objects.

 The difference between apply and call

 For apply and call, the functions are exactly the same, but the way of accepting parameters is different. For example, there is a function defined as follows:

var func = function(arg1, arg2) {
     
};
Copy after login

can be called as follows:

func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])
Copy after login

where this is the context you want to specify, it can be any JavaScript object (everything in JavaScript is an object), call needs to The parameters are passed in order, and apply puts the parameters in an array.

 In JavaScript, the number of parameters of a function is not fixed, so if conditions apply, use call when the number of your parameters is clearly known.

 When you are unsure, use apply, and then push the parameters into the array and pass them in. When the number of parameters is uncertain, all parameters can be traversed inside the function through the arguments array.

 In order to consolidate and deepen memory, here are some common uses:

 1. Append

var array1 = [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] */
Copy after login

between arrays 2. Get the maximum and minimum values ​​in the array

var  numbers = [5, 458 , 120 , -215 ];
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458
Copy after login

number itself does not have a max method, but Math does , we can use its method with call or apply.

  3. Verify whether it is an array (provided that the toString() method has not been overridden)

functionisArray(obj){
    returnObject.prototype.toString.call(obj) === '[object Array]' ;
}
Copy after login

4. Class (pseudo) array uses the array method

var domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));
Copy after login

There is a kind of pseudo array in Javascript object structure. What is more special is the arguments object, as well as calls like getElementsByTagName, document.childNodes, etc. The NodeList objects they return are pseudo arrays. The push, pop and other methods under Array cannot be applied.

  But we can use Array.prototype.slice.call to convert it into a real array object with length property, so that domNodes can apply all methods under Array.

 In-depth understanding of the use of apply and call

 Now I will borrow an interview question to gain a deeper understanding of apply and call.

Define a log method so that it can proxy the console.log method. The common solution is:

function log(msg) {
  console.log(msg);
}
log(1);    //1
log(1,2);    //1
Copy after login

The above method can solve the most basic needs, but when the number of parameters passed in is uncertain, the above method The method will be invalid. At this time, you can consider using apply or call. Note that the number of parameters passed in here is uncertain, so using apply is the best. The method is as follows:

function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2
Copy after login

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

log("hello world");    //(app)hello world
Copy after login

How to do it more elegantly? At this time, you need to think that the arguments parameter is a pseudo array, and convert it into a standard through Array.prototype.slice.call Array, then use the array method unshift, like this:

function log(){
  var args = Array.prototype.slice.call(arguments);
  args.unshift('(app)');
  
  console.log.apply(console, args);
};
Copy after login

bind

  说完了 apply 和 call ,再来说说bind。bind() 方法与 apply 和 call 很相似,也是可以改变函数体内 this 的指向。

  MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind()方法的第一个参数作为 this,传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

  直接来看看具体如何使用,在常见的单体模式中,通常我们会使用 _this , that , self 等保存 this ,这样我们可以在改变了上下文之后继续引用到它。 像这样:

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

由于 Javascript 特有的机制,上下文环境在 eventBind:function(){ } 过渡到 $('.someClass').on('click',function(event) { }) 发生了改变,上述使用变量保存 this 这些方式都是有用的,也没有什么问题。当然使用 bind() 可以更加优雅的解决这个问题:

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

在上述代码里,bind() 创建了一个函数,当这个click事件绑定在被调用的时候,它的 this 关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。因此,这里我们传入想要的上下文 this(其实就是 foo ),到 bind() 函数中。然后,当回调函数被执行的时候, this 便指向 foo 对象。再来一个简单的栗子:

var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3
Copy after login

这里我们创建了一个新的函数 func,当使用 bind() 创建一个绑定函数之后,它被执行的时候,它的 this 会被设置成 foo , 而不是像我们调用 bar() 时的全局作用域。

有个有趣的问题,如果连续 bind() 两次,亦或者是连续 bind() 三次那么输出的值是什么呢?像这样:

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(); //?
Copy after login

答案是,两次都仍将输出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

apply、call、bind比较

  那么 apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个栗子:

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

    三个输出的都是81,但是注意看使用 bind() 方法的,他后面多了对括号。

 也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用 bind() 方法。而 apply/call 则会立即执行函数。

 再总结一下:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;

apply 、 call 、bind 三者都可以利用后续参数传参;

bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template