JS中的call,apply和bind

梳理一下call,apply和bind,並儘量將其應用到實際開發環境中。

​
/*apply()方法*/
function.apply(thisObj[, argArray])

/*call()方法*/
function.call(thisObj[, arg1[, arg2[, [,...argN]]]]);

/*bind()方法*/
function.bind(thisArg[, arg1[, arg2[, ...]]])
​

使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數。

  • apply:調用一個對象的一個方法,用另一個對象替換當前對象。例如:B.apply(A, arguments);即A對象應用B對象的方法。
  • call:調用一個對象的一個方法,用另一個對象替換當前對象。例如:B.call(A, args1,args2);即A對象調用B對象的方法。
  • bind: 函數會創建一個新綁定函數(bound function,BF)。它包裝了原函數對象。調用綁定函數通常會導致執行包裝函數.

call/apply的共同之處:

call 和 apply 都是爲了改變某個函數運行時的上下文(context)而存在的,換句話說,就是爲了改變函數體內部 this 的指向。 call 和 apply 是爲了動態改變 this 而出現的,當一個 object 沒有某個方法但是其他的對象有,我們可以藉助call或apply用其它對象的方法來操作。

call/apply的不同之處:

傳入的參數列表形式不同:

  • apply:最多只能有兩個參數——新this對象和一個數組argArray。如果給該方法傳遞多個參數,則把參數都寫進這個數組裏面,當然,即使只有一個參數,也要寫進數組裏。如果argArray不是一個有效的數組或arguments對象,那麼將導致一個TypeError。如果沒有提供argArray和thisObj任何一個參數,那麼Global對象將被用作thisObj,並且無法被傳遞任何參數。
  • call:它可以接受多個參數,第一個參數與apply一樣,後面則是一串參數列表。這個方法主要用在js對象各方法相互調用的時候,使當前this實例指針保持一致,或者在特殊情況下需要改變this指針。如果沒有提供thisObj參數,那麼 Global 對象被用作thisObj。

bind的特殊之處

call/apply使用的時候,函數就立即執行了,而bind只是創建了一個包裝着原函數對象的新的綁定函數,所以我們需要再手動的去執行這個新的綁定函數。其傳參方式跟call一樣。其作用和call/apply的作用一樣,爲了改變某個函數運行時的this指向。

call/apply/bind代碼實例

示例代碼:

(1)基本用法

​
function add(a,b){
  return a+b;  
}
function sub(a,b){
  return a-b;  
}
var a1 = add.apply(sub,[4,2]);  //sub調用add的方法
var a2 = sub.apply(add,[4,2]);
alert(a1);  //6     
alert(a2);  //2

/*call的用法*/
var a1 = add.call(sub,4,2);

//bind的用法(需要執行bind返回的這個函數)
var a1 = add.bind(sub, 4, 2)();

​

(2)實現繼承

原理: 寫一個方法,然後讓另外一個新的對象來繼承該方法。

​
//Animal方法(也可看做Animal類)
function Animal(name){
  this.name = name;
  this.say = function(){
        alert(this.name);    
    }    
}

//cat方法繼承了Animal方法
function Cat(name){
  Animal.apply(this,[name]);  
  
  //call的用法
  //Animal.call(this,name);
  
  //bind的用法
  //Animal.bind(this, name)();
}

//cat就可以miaomiaomiao
var cat = new Cat("miaomiaomiao~");
cat.say();
​

(3)多重繼承

​
function Class10(){
  this.showSub = function(a,b){
        alert(a - b);
    }   
}

function Class11(){
  this.showAdd = function(a,b){
        alert(a + b);
    }  
}

function Class12(){
  Class10.apply(this);
  Class11.apply(this);   
  
  //call的用法
  // Class10.call(this);
  //Class11.call(this);
  
  //apply的用法
  // Class10.bind(this)();
  //Class11.bind(this)();
}

var c2 = new Class12();
c2.showSub(3,1);    //2
c2.showAdd(3,1);    //4
​

apply的一些其他巧妙用法

(1)Math.max 可以實現得到數組中最大的一項:

因爲Math.max不支持Math.max([param1,param2])也就是數組,但是它支持Math.max(param1,param2...),所以可以根據apply的特點來解決 var max=Math.max.apply(null,array),這樣就輕易的可以得到一個數組中的最大項(apply會將一個數組轉換爲一個參數接一個參數的方式傳遞給方法)這塊在調用的時候第一個參數給了null,這是因爲沒有對象去調用這個方法,我只需要用這個方法幫我運算,得到返回的結果就行,所以直接傳遞了一個null過去。

用這種方法也可以實現得到數組中的最小項:Math.min.apply(null,array)

​
var arr = [3, 4, 6, 9]
var max = Math.max.apply(null, arr)
var min = Math.min.apply(null, arr)
​

(2)Array.prototype.push可以實現兩個數組的合併

push只能依次往數組push單個項,因此可以:

​
var arr1=new Array("1","2","3");

var arr2=new Array("4","5","6");

Array.prototype.push.apply(arr1,arr2);
//得到合併後數組的長度,因爲push就是返回一個數組的長度
​

也可以這樣理解,arr1調用了push方法,參數是通過apply將數組轉換爲參數列表的集合.

通常在什麼情況下,可以使用apply類似Math.max等之類的特殊用法:
一般在目標函數只需要n個參數列表,而不接收一個數組的形式,可以通過apply的方式巧妙地解決這個問題。

想知道更多,可以點擊下面:

關於call,點我。

關於apply,點我

關於bind,點我。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章