梳理一下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的方式巧妙地解決這個問題。
想知道更多,可以點擊下面: