Home >Web Front-end >JS Tutorial >Turn on the usage tour mode of apply, call and bind in Javascript_javascript skills

Turn on the usage tour mode of apply, call and bind in Javascript_javascript skills

WBOY
WBOYOriginal
2016-05-16 15:34:461097browse

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.

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 context" and "runtime context" as well as "context can be changed".

Let me first give you a code example:

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"} and we don’t want to redefine its say method, 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

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 can use call or apply to operate using methods of other objects.

The difference between apply and call

For both 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) { 
};

can be called as follows:

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

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

In JavaScript, the number of parameters of a function is not fixed, so if you want to apply conditions, 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 between arrays

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] */

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

Number itself does not have a max method, but Math does, so 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){ 
  return Object.prototype.toString.call(obj) === '[object Array]' ;
}

4. Class (pseudo) array uses array method

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

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

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

Deep understanding of the use of apply and call

The following is [borrowing an interview question] to understand apply and call more deeply.

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

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

The above method can solve the most basic needs, but when the number of parameters passed in is uncertain, the above method is invalid. At this time, you can consider using apply or call. Pay attention to how many parameters are passed in here. is uncertain, so it is best to use apply. The method is as follows:

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

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

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

How to do it more elegantly? At this time, you need to think that the arguments parameter is a pseudo array, convert it into a standard array through Array.prototype.slice.call, and 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);
};

bind

After talking about apply and call, let’s talk about bind. The bind() method is very similar to apply and call, and can also change the pointer of this in the function body.

MDN’s explanation is: The bind() method will create a new function, called a binding function. When this binding function is called, the binding function will be based on the first value passed into the bind() method when it was created. The parameter is this, and the second and subsequent parameters passed into the bind() method plus the parameters of the bound function itself when running are used in order as the parameters of the original function to call the original function.

Let’s take a look at how to use it directly. In the common singleton mode, we usually use _this, that, self, etc. to save this so that we can continue to refer to it after changing the context. Like this:

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

由于 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));
  }
}

在上述代码里,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

这里我们创建了一个新的函数 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(); //?

答案是,两次都仍将输出 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

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

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

再总结一下:

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用后续参数传参;

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

好了,本文关于开启Javascript中apply、call、bind的用法之旅模式的相关教程,到此给大家介绍完了,希望大家喜欢。

Statement:
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