The difference and use of call, apply, bind

Almost every time in the interview, I will ask a question about call, apply, and bind in js, such as...

  • How to use call and apply to do inheritance
  • The difference between apply, call and bind and the main application scenarios

First of all, what is the meaning of these three functions?

The answer is: change the context when the function is executed , and more specifically, change the this point of the function when it is running .

With this understanding, let's take a look at how to use these three functions.

let obj = {name: 'tony'};
  
  function Child(name){
    this.name = name;
  }
  
  Child.prototype = {
    constructor: Child,
    showName: function(){
      console.log(this.name);
    }
  }
  var child = new Child('thomas');
  child.showName(); // thomas
  
  //  call,apply,bind使用
  child.showName.call(obj);
  child.showName.apply(obj);
  let bind = child.showName.bind(obj); // 返回一个函数
  bind(); // tony

 

We took other people’s showName method and dynamically changed its context to help ourselves output the information. In the final analysis, we realized reuse

The bind method is to change the this of fn to the result we want in advance, and prepare the corresponding parameter values, which will be used later, and can be executed directly. That is to say, bind can also change the point of this, but with The difference between apply and call is that they will not be executed immediately (as in the previous example)

Note: The bind method is not compatible under IE6~8.

the difference

It seems that the functions of the three functions above are similar, and they do almost the same thing, so why should there be three guys? Just leave one. So in fact, what they do is essentially the same dynamic change of this context, but there are still some differences...

  • The difference between call, apply and bind

Call and apply change the this context of the function and execute the function, while bind returns a function after changing the context.

  • The difference between call and apply

The difference between the two of them lies in the difference in parameters. The first parameter of call and apply is the object whose context is to be changed, while call starts from the second parameter in the form of a parameter list. Apply is to change the context object. The parameter is placed in an array as its second parameter.

Example 1: Find the most value in the array
​
let arr1 = [1, 2, 19, 6];
console.log(Math.max.call(null, 1,2,19,6)); // 19
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); //  19 直接可以用arr1传递进去

​
Example 2:
function fn() {
    console.log(this);
}
// apply方法结果同下
fn.call(); // 普通模式下this是window,在严格模式下this是undefined
fn.call(null); // 普通模式下this是window,在严格模式下this是null
fn.call(undefined); // 普通模式下this是window,在严格模式下this是undefined

 

application:

  • Convert the pseudo-array into an array (objects with length attribute, dom nodes, function arguments)

Pseudo arrays in js (for example, elements obtained through document.getElementsByTagName, objects with length attributes) have length attributes, and the elements can be accessed through 0, 1, 2... subscripts, but there is no push, pop in Array And other methods. You can use call, apply to convert into a real array, you can use the array method

case1: dom节点:

 

<div class="div1">1</div>
<div class="div1">2</div>
<div class="div1">3</div>

let div = document.getElementsByTagName('div');
console.log(div); // HTMLCollection(3) [div.div1, div.div1, div.div1] 里面包含length属性

let arr2 = Array.prototype.slice.call(div);
console.log(arr2); // 数组 [div.div1, div.div1, div.div1]

 

But this does not apply to IE6~8, it will report an error:

SCRIPT5014: Array.prototype.slice: 'this' 不是 JavaScript 对象 (报错)
那么在IE6~8下就只能通过循环一个个加到数组中了:
for (var i = 0; i < oLis.length; i++) {
    ary[ary.length] = oLis[i];
}
基于IE6~8和标准浏览器中的区别,抽取出类数组对象转换为数组的工具类:
function listToArray(likeAry) {
    var ary = [];
    try {
        ary = Array.prototype.slice.call(likeAry);
    } catch (e) {
        for (var i = 0; i < likeAry.length; i++) {
            ary[ary.length] = likeAry[i];
        }
    }
    return ary;
}

 

case2 : arguments in fn
function fn10() {
    return Array.prototype.slice.call(arguments);
}
console.log(fn10(1,2,3,4,5)); // [1, 2, 3, 4, 5]

Note: There is no compatibility problem with the method of borrowing arrays for arguments.

case3 : object with length attribute

let obj4 = {
    0: 1,
    1: 'thomas',
    2: 13,
    length: 3 // 一定要有length属性
};

console.log(Array.prototype.slice.call(obj4)); // [1, "thomas", 13]

 

  • Array splicing, adding

let arr1 = [1,2,3];
let arr2 = [4,5,6];

//数组的concat方法:返回一个新的数组
let arr3 = arr1.concat(arr2); 
console.log(arr3); // [1, 2, 3, 4, 5, 6]

console.log(arr1); // [1, 2, 3] 不变
console.log(arr2); // [4, 5, 6] 不变
// 用 apply方法
[].push.apply(arr1,arr2);  // 给arr1添加arr2
console.log(arr1); // [1, 2, 3, 4, 5, 6]
console.log(arr2); // 不变

 

  • Determine the variable type

let arr1 = [1,2,3];
let str1 = 'string';
let obj1 = {name: 'thomas'};
//
function isArray(obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(fn1(arr1)); // true

//  判断类型的方式,这个最常用语判断array和object,null(因为typeof null等于object)  
console.log(Object.prototype.toString.call(arr1)); // [object Array]
console.log(Object.prototype.toString.call(str1)); // [object String]
console.log(Object.prototype.toString.call(obj1)); // [object Object]
console.log(Object.prototype.toString.call(null)); // [object Null]

 

 

  • Use call and apply for inheritance

function Animal(name){      
    this.name = name;      
    this.showName = function(){      
        console.log(this.name);      
    }      
}      

function Cat(name){    
    Animal.call(this, name);    
}      

// Animal.call(this) 的意思就是使用this对象代替Animal对象,那么
// Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了
var cat = new Cat("TONY");     
cat.showName();   //TONY
  • Multiple inheritance

function Class1(a,b) {
    this.showclass1 = function(a,b) {
      console.log(`class1: ${a},${b}`);
    }
  }

  function Class2(a,b) {
    this.showclass2 = function(a,b) {
      console.log(`class2: ${a},${b}`);
    }
  }

  function Class3(a,b,c) {
    Class1.call(this);
    Class2.call(this);
  }

  let arr10 = [2,2];
  let demo = new Class3();
  demo.showclass1.call(this,1); // class1: 1,undefined
  demo.showclass1.call(this,1,2); // class1: 1,1
  demo.showclass2.apply(this,arr10); // class2: 1,2

 

Guess you like

Origin blog.csdn.net/AN0692/article/details/114929254