1. 程式人生 > 實用技巧 >js apply() call() bind() 的使用

js apply() call() bind() 的使用

bind ,call,apply這三者都是用來改變函式的this物件的指向的。

call和apply其實是同一個東西,區別只有引數不同。

其實call和apply ,只要你呼叫呼叫一個函式的時候就可以用,任何時候,任何函式,隨便用,但是沒有意義,但是我們得知道什麼場景合適去用。

call 和 apply 都是為了改變某個函式執行時的 context 即上下文而存在的,換句話說,就是為了改變函式體內部 this 的指向。因為 JavaScript 的函式存在「定義時上下文」和「執行時上下文」以及「上下文是可以改變的」這樣的概念。

obj.call(thisObj, arg1, arg2, ...);

obj.apply(thisObj, [arg1, arg2, ...]);

兩者作用一致,都是把obj(即this)繫結到thisObj,這時候thisObj具備了obj的屬性和方法。或者說thisObj『繼承』了obj的屬性和方法。

apply:

定義:應用某一物件的一個方法,用另一個物件替換當前物件。

Function.apply(obj,args)方法能接收兩個引數

obj:這個物件將代替Function類裡this物件
args:這個是陣列,它將作為引數傳給Function(args-->arguments)

call:

和apply的意思一樣,只不過是引數列表不一樣.

Function.call(obj,[param1[,param2[,…[,paramN]]]])

obj:這個物件將代替Function類裡this物件
params:這個是一個引數列表

問題來了-->什麼情況下用apply,什麼情況下用call???

在給物件引數的情況下,如果引數的形式是陣列的時候,用apply。

引數列表是(param1,param2,param3),這樣就可以用call來實現了,也就是直接指定引數列表對應值的位置(方法.call(this,param1,param2,param3));

看個例子:

 var xw = {
      name : 
"小王", gender : "男", age : 24, say : function(school,grade) { alert(this.name + " , " + this.gender + " ,今年" + this.age + " ,在" + school + "上" + grade); } } var xh = { name : "小紅", gender : "女", age : 18 }

call來說是這樣的:xw.say.call(xh,"實驗小學","六年級");

apply來說是這樣的:xw.say.apply(xh,["實驗小學","六年級啦啦啦"]);

看到區別了嗎,call後面的引數與say方法中是一一對應的,而apply的第二個引數是一個數組,陣列中的元素是和say方法中一一對應的,這就是兩者最大的區別。

那麼bind怎麼傳參呢?bind返回的仍然是一個函式,所以我們還可以在呼叫的時候再進行傳參:xw.say.bind(xh)("實驗小學","六年級");

後面會說到bind。先了解一下。

apply的一些其他巧妙用法:

在呼叫apply方法的時候,第一個引數是物件(this), 第二個引數是一個數組集合,在呼叫某個方法的時候,他需要的不是一個數組,但是為什麼他給我一個數組我仍然可以將陣列解析為一個一個的引數,這個就是apply的一個巧妙的用處:

可以將一個數組預設的轉換為一個引數列表([param1,param2,param3] 轉換為 param1,param2,param3) ,這個如果讓我們用程式來實現將陣列的每一個項,來裝換為引數的列表,可能都得費一會功夫,藉助apply的這點特性,所以就有了以下高效率的方法:

(1)Math.max 可以實現得到陣列中最大的一項

因為Math.max 引數裡面不支援Math.max([param1,param2]) 也就是陣列

但是它支援Math.max(param1,param2,param3…),所以可以根據剛才apply的那個特點來解決 var max=Math.max.apply(null,array),這樣輕易的可以得到一個數組中最大的一項(apply會將一個數組裝換為一個引數接一個引數的傳遞給方法)

這塊在呼叫的時候第一個引數給了一個null,這個是因為沒有物件去呼叫這個方法,我只需要用這個方法幫我運算,得到返回的結果就行,.所以直接傳遞了一個null過去

(2)Math.min 可以實現得到陣列中最小的一項

同樣和 max是一個思想 var min=Math.min.apply(null,array);

(3)Array.prototype.push 可以實現兩個數組合並

同樣push方法沒有提供push一個數組,但是它提供了push(param1,param,…paramN) 所以同樣也可以通過apply來裝換一下這個陣列,即:

1 let arr1=new Array("1","2","3");    
2 let arr2=new Array("4","5","6");  
3 Array.prototype.push.apply(arr1,arr2);  
4 console.log(arr1);//[1,2,3,4,5,6]

也可以這樣理解,arr1呼叫了push方法,引數是通過apply將陣列裝換為引數列表的集合.

通常在什麼情況下,可以使用apply類似Math.min等之類的特殊用法:

一般在目標函式只需要n個引數列表,而不接收一個數組的形式([param1[,param2[,…[,paramN]]]]),可以通過apply的方式巧妙地解決這個問題!

bind:

Function.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg 當繫結函式被呼叫時,該引數會作為原函式執行時的 this 指向。當使用 new 操作符呼叫繫結函式時,該引數無效。

arg1, arg2, … (可選)當繫結函式被呼叫時,這些引數加上繫結函式本身的引數會按照順序作為原函式執行時的引數。

bind()方法主要就是將函式繫結到某個物件,bind()會建立一個函式,函式體內的this物件的值會被繫結到傳入bind()中的第一個引數的值,例如:f.bind(obj),實際上可以理解為obj.f(),這時f函式體內的this自然指向的是obj; 先看一下官網例子:
const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};

const unboundGetX = module.getX;
console.log(unboundGetX());//undefined //在全域性作用域呼叫 this指向window


const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());//42

call , bind ,apply 區別:

看一個例子:

 1 var xw = {
 2        name : "小王",
 3        gender : "男",
 4        age : 24,
 5        say : function() {
 6              alert(this.name + " , " + this.gender + " ,今年" + this.age);                                
 7        }
 8 }
 9 var xh = {
10        name : "小紅",
11        gender : "女",
12        age : 18
13 }
14 xw.say();

顯示的肯定是小王 , 男 , 今年24。

那麼如何用xw的say方法來顯示xh的資料呢????

call可以這樣:xw.say.call(xh);

apply可以這樣:xw.say.apply(xh);

bind來說需要這樣:xw.say.bind(xh)();

看到區別了嗎?call和apply都是對函式的直接呼叫,而bind方法返回的仍然是一個函式,因此後面還需要()來進行呼叫才可以。

學無止境,砥礪前行,fighting!!!