javascript中的call、apply、bind用法及區(qū)別

一.call、apply、bind作用

在JavaScript中,call、apply和bind是Function對(duì)象自帶的三個(gè)方法。這三個(gè)函數(shù)的存在意義是什么?答案就是改變函數(shù)運(yùn)行時(shí)的this指向。下面我們通過實(shí)際例子來介紹這三個(gè)方法的使用和區(qū)別。

二.call

語法:fn.call(thisArg,arg1,arg2,...)

thisArg:函數(shù)fn運(yùn)行時(shí),該函數(shù)中的this綁定到thisArg上。
arg1,arg2,...:函數(shù)fn所需的參數(shù),是個(gè)list

我們直接看例子:

var a ={
    name : "test",
    fn : function (a,b) {
        console.log(this.name, a + b)
    }
}
var b={name:'test1'}
a.fn(1,2) //test 3
a.fn.call(b,1,2) //test1 3

執(zhí)行 a.fn(1,2),fn中的this指向a,所以輸出 test 3
執(zhí)行 a.fn.call(b,1,2),通過call改變了fn中的this指向?yàn)閎,所以輸出 test1 3

注意事項(xiàng):

  1. thisArg不傳,或者傳null,undefined, 函數(shù)中的this指向window對(duì)象
  2. thisArg為原始值(數(shù)字,字符串,布爾值),函數(shù)中this指向該原始值的自動(dòng)包裝對(duì)象(如 String、Number、Boolean)
  3. thisArg為一個(gè)對(duì)象,函數(shù)中的this指向這個(gè)對(duì)象
  4. thisArg為一個(gè)函數(shù)名,函數(shù)中的this指向該函數(shù)
  5. 前四點(diǎn)是默認(rèn)在非嚴(yán)格模式下,如果在嚴(yán)格模式下,會(huì)略有不同。

我們直接看例子:

function a(params) {
    console.log(this);
}
function b() {}
var obj = {
    name: '這是一個(gè)屌絲'
};

//                  正常模式下              嚴(yán)格模式下
a.call();           //window               undefined
a.call(null);       //window               null
a.call(undefined);  //window               undefined
a.call(1);          //Number{1}            1
a.call('');         //String{''}           ''
a.call(true);       //Boolean{true}        true
a.call(b);          //function b(){}       function b(){}
a.call(obj);        //Object               Object

三.apply

語法:fn.call(thisArg,[arg1,arg2,...])或者 fn.call(thisArg,{0:arg1,1:arg2,...,lenght:總個(gè)數(shù)})

thisArg:函數(shù)fn運(yùn)行時(shí),該函數(shù)中的this綁定到thisArg上。
[arg1,arg2,...]或者形如{0:arg1,1:arg2,...,lenght:總個(gè)數(shù)}:函數(shù)fn所需的參數(shù),是個(gè)數(shù)組或者類數(shù)組,call函數(shù)會(huì)自動(dòng)將數(shù)組或類數(shù)組的每個(gè)值分開成列表然后給函函數(shù)fn

例子和上面一樣,只需要把call換成apply即可。其他都一樣,包括上面call的幾點(diǎn)注意事項(xiàng)即不傳或者傳null等。

四.bind

語法:fn.bind(thisArg,arg1,arg2,...)()

thisArg:函數(shù)fn運(yùn)行時(shí),該函數(shù)中的this綁定到thisArg上。
arg1,arg2,...:函數(shù)fn所需的參數(shù),是個(gè)list

bind其實(shí)和call類似,包括上面call的幾點(diǎn)注意事項(xiàng)即不傳或者傳null等,只不過后面多個(gè)()。我們直接看例子

 var a = {
    name: "test",
    fn: function (a, b) {
        console.log(this.name, a + b)
    }
}
var b = {
    name: 'test1'
}
a.fn.bind(b, 1, 2)

運(yùn)行上面代碼,我們發(fā)現(xiàn)控制臺(tái)并沒有輸出,所以我們可以看出bind 是創(chuàng)建一個(gè)新的函數(shù),我們必須要手動(dòng)去調(diào)用。我們更改代碼:

var a = {
    name: "test",
    fn: function (a, b) {
        console.log(this.name, a + b)
    }
}
var b = {
    name: 'test1'
}
a.fn.bind(b, 1, 2) //test1 3

上面我們手動(dòng)調(diào)用,發(fā)現(xiàn)正確輸出結(jié)果。

五.call apply bind三者區(qū)別總結(jié)

1.call和apply用法一樣,唯一的區(qū)別是call的參數(shù)為列表,apply參數(shù)為數(shù)組
2.bind和call用法一樣,唯一的區(qū)別是call會(huì)自執(zhí)行函數(shù),bind需要手動(dòng)調(diào)用函數(shù)

六.應(yīng)用

1.繼承

var Person = function (name, age) {
    this.name = name;
    this.age = age;
};
var Girl = function (name) {
    Person.call(this, name);
};
var Boy = function (name, age) {
    Person.apply(this, arguments);
}
var Boy1 = function (name, age) {
    Person.bind(this, name)();
}
var g = new Girl('xiaohong');
var b = new Boy('xiaoming', 100);
var b1 = new Boy1('xiaowang', 100);
console.log(g); //{name: "xiaohong", age: undefined}
console.log(b); //{name: "xiaoming", age: 100}
console.log(b1); //{name: "xiaowang", age: undefined}

上面例子,我們定義了四個(gè)構(gòu)造函數(shù),通過new實(shí)例化調(diào)用Girl、Boy、Boy1這三個(gè)構(gòu)造函數(shù),在這三個(gè)構(gòu)造函數(shù)中分別使用call、apply、bind繼承Person的屬性。
我們來看下它到底是怎么繼承的?

 var Person = function (name, age) {
      this.name = name;
      this.age = age;
};
var Girl = function (name) {
    Person.call(this, name);
};  
var g = new Girl('xiaohong');

1.先執(zhí)行g=new Girl('xiaohong'); 此時(shí)執(zhí)行Girl函數(shù),并執(zhí)行函數(shù)里面的代碼Person.call(this, name);
2.Person.call(this, name);中的this指向調(diào)用方,即實(shí)例g. 通過call方法后,會(huì)調(diào)用person函數(shù),本來person的this指向被調(diào)用方,此時(shí)person函數(shù)的this被改變成實(shí)例g
3.所以就變成g.name=name; g.age=age
4.所以通過girl實(shí)例化出的g相當(dāng)于繼承了person里面的屬性

2.求數(shù)組中的最大和最小值

var ary = [0, 1, 1, 3, 4, 5, 6, 7];
console.log(Math.max(0, 1, 1, 3, 4, 5, 6, 7)); //7
console.log(Math.min(0, 1, 1, 3, 4, 5, 6, 7)); //0
var max = Math.max.apply(null, ary);
var min = Math.min.apply(null, ary);
console.log(max,min); //7 0

上面例子可以看出,正常情況下,Math.max和Math.min的參數(shù)為必須為列表,上面只用0-7八個(gè)數(shù)字還好,但如果數(shù)據(jù)很多,都放到參數(shù)會(huì)比較麻煩。

所以我們借助apply可以將數(shù)組轉(zhuǎn)換成列表的功能,這樣我們就可以直接傳遞一個(gè)變量了。第一個(gè)參數(shù)這里使用null,實(shí)際換成其他都可以(如隨便一個(gè)字符串、數(shù)字、對(duì)象等),這里主要使用的是call函數(shù)的 數(shù)組轉(zhuǎn)列表功能。

3.類數(shù)組轉(zhuǎn)數(shù)組

Array.prototype.slice.call(arrayLike) 或者 Array.prototype.slice.apply(arrayLike)

具體可以戳這javascript中的偽(類)數(shù)組和數(shù)組

4.數(shù)組追加

在js中我們往數(shù)組追加元素,一般使用push方法。

  var arr1 = [1,2,3];
  var arr2 = [4,5,6];
  arr1.push(4,5,6)
  console.log(arr1) //[1,2,3,4,5,6]

我們也可以使用apply方法:

var arr1 = [1,2,3];
var arr2 = [4,5,6];
[].push.apply(arr1,arr2)
console.log(arr1) //[1,2,3,4,5,6]

上面代碼意思表示:[]調(diào)用push方法,然后通過call將push方法中的this指向arr1,并將arr2轉(zhuǎn)變成參數(shù)列表。這樣就達(dá)到合并的目的。

5. 判斷變量類型

Object.prototype.toString.call/apply(object);

具體詳見另一篇文章toString()和Object.prototype.toString.call()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容