關於JS中call 、apply 和bind

call()、apply()、bind() 都是用來改變函數運行時的this指向面試

也就是改變函數執行的上下文,被稱爲改變this指向的三兄弟。數組

先記住如下this的總結,便於如下例子中this指向的理解:markdown

  • 在方法中(該方法不是箭頭函數定義的),this表示該方法所屬的對象;
  • 如何單獨使用,this表示全局對象;
  • 在函數中,this表示全局對象;
  • 在函數中,在嚴格模式下,this是未定義的(undefined);
  • 在事件中,this表示接受事件的元素;
  • call( )、apply( )能夠將this引用到任何對象;

1、call

一、簡單理解call

經過一個demo來理解call( )的用法:app

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName();//leaf 26
person.getName.call(person2);//ice 18
複製代碼

getName( )是person這個對象的一個方法,在方法中,this表示該方法所屬的對象,因此getName方法中的this指的是person這個對象。函數

call( )能夠改變this的指向,它能夠把getName方法所屬的對象指向person2。oop

因此:ui

call( )容許爲不一樣的對象分配和調用屬於一個對象的函數/方法。this

二、帶參數的call

call( )方法能夠接受參數,第一個參數是改變上下文的對象,從第二個參數開始以參數列表的形式展現,用逗號隔開。spa

var person = {
  name:'leaf',
  age:26,
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.call(person2, '英國','倫敦');//ice 18 英國 倫敦
複製代碼

2、apply

一、簡單理解apply

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName();//leaf 26
person.getName.apply(person2);//ice 18
複製代碼

二、帶參數的apply

apply( )方法接受數組形式的參數。code

var person = {
  name: 'leaf',
  age: 26,
  city: '廣西',
  country: '中國',
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name: 'ice',
  age: 18
}

person.getName.apply(person2, ['美國','紐約']);//ice 18 美國 紐約
//等價於
// person.getName.call(person2, '英國','倫敦');//ice 18 英國 倫敦
複製代碼

總結:

apply( )和call( )方法很類似,那apply( )和call( )的區別主要在於參數的區別:

  • call( )方法接受參數;
  • apply( )方法接受數組形式的參數;

除了接受參數形式不一樣以外,call( )和apply( )行爲都是一致的。

3、bind

bind() 方法一樣也是能夠改變this的指向,可是和call、apply不一樣的是bind( )返回的是改變上下文的一個函數,而且不會立刻執行,須要用的時候再執行。

var person = {
  name:'leaf',
  age:26,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.bind(person2)();//ice 18
複製代碼

bind( )方法後邊多了個()外,結果和call、apply返回的結果都是一致!

總結:

bind方法返回的是一個新函數,必須調用它纔會被執行。

4、總結call、apply和bind的用法示例:

一、對比沒有參數的狀況下:

var name = 'qing',age = 20;
var person = {
  name:'leaf',
  personAge:this.age,
  getName:function(){
  console.log(this.name+' '+this.age);
}
}

var person2 = {
  name:'ice',
  age:18
}

person.getName.call(person2);        //ice 18
person.getName.apply(person2);      //ice 18
person.getName.bind(person2)();     //ice 18
複製代碼

二、對比傳參的狀況下:

var person = {
  name: 'leaf',
  age: 26,
  city: '廣西',
  country: '中國',
  getName: function(country,city){
    console.log(this.name + ' ' + this.age + ' ' + country + ' ' + city);
  }
}

var person2 = {
  name: 'ice',
  age: 18
}

person.getName.call(person2, '英國','倫敦');  //ice 18 英國 倫敦
person.getName.apply(person2, ['美國','紐約']); //ice 18 美國 紐約
person.getName.bind(person2, '中國','上海')();  //ice 18 中國 上海
person.getName.bind(person2, ['中國','上海'])();  //ice 18 中國,上海 undefined
複製代碼

總結:

  • 不傳參的狀況下,除bind方法後邊多個()外,返回的結果和call、apply都是同樣的。

  • 傳參的狀況下,call、apply、bind第一個參數都是改變this的指向對象,主要差異在第二個參數:

  • ​ call的參數以參數列表的形式直接存放,參數之間用逗號分隔;

  • ​ apply的參數以數組的形式存放,參數必須放置在一個數組裏面;

  • ​ bind的參數存放形式和call是同樣的,都是以參數列表的形式存放,參數直接用逗號分隔。

5、相關面試題

  1. 如何利用call、apply、bind來求一個數組中的最大或最小值?
var arr = [7, 8, 2, 1, 4, 3, 5, 6, 0];
console.log(Math.max.apply(Math, arr)); //8

console.log(Math.max.call(Math, 7, 8, 2, 1, 4, 3, 5, 6, 0)); //8
console.log(Math.max.bind(Math, 7, 8, 2, 1, 4, 3, 5, 6, 0)()); //8
console.log(Math.max.call(Math, arr)); //NaN
複製代碼

求一個數組的最大或最小值,最方便的方法就是使用Math.max.apply方法。

注意:

在上邊的代碼中,由於不須要this去調用Math方法,apply的第一個參數能夠寫成null、underfined、window 、document均可以。

console.log(Math.max.apply(null, arr)); //8
複製代碼

那你可能會問Math.max( )原本就能夠求一組數中的最大值,那爲何不直接使用Math.max( )呢?

由於Math.max( )的參數只能是Number類型的參數,若是放置一個數組會報錯:

var arr = [7, 8, 2, 1, 4, 3, 5, 6, 0];
console.log(Math.max(arr)); //math is not defined

console.log(Math.max(7, 8, 2, 1, 4, 3, 5, 6, 0)); //8
console.log(Math.max(...arr));//8 也可使用擴展運算符,將數組轉換成Number類型的參數
複製代碼

而apply( )能夠直接接受一個數組,能夠將數組參數轉換成列表參數傳入,從而直接求數組的最大值。

最小值就不講了,和Math.max同樣的,直接Math.min替換Math.max便可。

  1. 如何利用call、apply來作繼承
  2. call、apply、bind的區別和主要應用場景
  3. 何時該用call、apply、bind?
相關文章
相關標籤/搜索