cocos2d - JS 進階主題 call() 、apply() 和 bind() 解析
Tips : Call 和 apply 非常類似 以Call方法為例.
Call方法 :
定義:
呼叫一個物件的一個方法,以另一個物件替換當前物件。
說明:
Call 方法可以用來代替另一個物件呼叫一個方法。
Call 方法可將一個函式的物件上下文從初始的上下文改變為由 thisObj 指定的新物件。
如果沒有提供 thisObj 引數,那麼 Global 物件被用作 thisObj。
JavaScript 程式碼 :
var Animal = cc.Sprite.extend({
name : null,
ctor: function(){
this._super();
this.name = "Animal";
},
showName: function(){
cc.log(this.name);
},
})
var Cat = cc.Sprite.extend({
name : null,
ctor: function(){
this._super();
this.name = "Cat";
},
})
var cat = new Cat();
var animal = new Animal();
animal.showName() //結果為Animal
cat.showName(); //報錯
animal.showName.call(cat); //結果為Cat
//通過call或apply方法,將原本屬於Animal物件的showName()方法交給物件cat來使用了。
//animal.showName.apply(cat,[]);
call 的意思是把 animal 的方法放到cat上執行,原來cat是沒有showName() 方法,現在是把animal 的showName()方法放到 cat上來執行,所以this.name 應該是 Cat
JavaScript 程式碼 :
function add(a,b)
{
alert(a+b);
}
function sub(a,b)
{
alert(a-b);
}
add.call(sub,3,1);
這個例子中的意思就是用 add 來替換 sub,add.call(sub,3,1) == add(3,1) ,所以執行結果為:alert(4);
注意:js 中的函式其實是物件,函式名是對 Function 物件的引用。
Call 和 Apply 的區別 :
定義一個log方法 :
function log(msg){
console.log(msg);
}
log(1) // 1
log(1, 2) // 1
可以看出來 這個方法只能接受一個引數, 雖然可以解決最基本的需求,但是當傳入引數的個數是不確定的時候,上面的方法就失效了,這個時候就可以考慮使用 apply 替代 call .
注意 :
這裡傳入多少個引數是不確定的,所以使用apply是最好的,方法如下:
function log(){
console.log.apply(console, arguments);
}
再次嘗試 :
log(1) // 1
log(1, 2) // 1 2
結果就正確了!
其實, 在 cocos2d - js 裡 cc.log 的實現方式正是如此 !
bind() 方法 :
bind方法本身和 apply 、call很類似, 也同樣是改變this指向的方法, 但是bind使用的地方與apply 和 call 有些不同.
注意 :
bind方法會建立一個新函式, 稱作繫結函式, 當呼叫bind函式時, 為以第一個引數為this(通常傳入的也是this), 傳入bind的第二個以及以後的引數加上繫結函式執行時本身的引數, 按照順序作為原函式的引數來呼叫函式.
在具體例項中, 我們通常用self、that等, 用來儲存this, 例如 :
var foo = {
num: 1,
eventBind: function(){
var self = this;
$('.someClass').on('click',function(event) {
console.log(self.num); //1
});
}
}
————————-下文為網路原文————————-
由於 Javascript 特有的機制,上下文環境在 eventBind:function(){ } 過渡到 $(‘.someClass’).on(‘click’,function(event) { }) 發生了改變,上述使用變數儲存 this 這些方式都是有用的,也沒有什麼問題。當然使用 bind() 可以更加優雅的解決這個問題:
var foo = {
bar : 1,
eventBind: function(){
$('.someClass').on('click',function(event) {
console.log(this.bar); //1
}.bind(this));
}
}
在上述程式碼裡,bind() 建立了一個函式,當這個click事件繫結在被呼叫的時候,它的 this 被傳入(呼叫bind()時傳入的引數)。因此,這裡我們傳入想要的上下文 this( foo ),到 bind() 函式中。然後,當回撥函式被執行的時候, this 便指向 foo 物件。
例如:
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
bar(); // undefined
var func = bar.bind(foo);
func(); // 3
這裡我們建立了一個新的函式 func,當使用 bind() 建立一個繫結函式之後,它被執行的時候,它的 this 會被設定成 foo , 而不是像我們呼叫 bar() 時的全域性作用域。
有個有趣的問題,如果連續 bind() 兩次,亦或者是連續 bind() 三次那麼輸出的值是什麼呢?像這樣:
var bar = function(){
console.log(this.x);
}
var foo = {
x:3
}
var sed = {
x:4
}
var func = bar.bind(foo).bind(sed);
func(); //?
var fiv = {
x:5
}
var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //?
答案是,兩次都仍將輸出 3 ,而非期待中的 4 和 5 。原因是,在Javascript中,多次 bind() 是無效的。更深層次的原因, bind() 的實現,相當於使用函式在內部包了一個 call / apply ,第二次 bind() 相當於再包住第一次 bind() ,故第二次以後的 bind 是無法生效的。
Apply 、Call 、 Bind 比較
那麼 apply、call、bind 三者相比較,之間又有什麼異同呢?何時使用 apply、call,何時使用 bind 呢。簡單的一個栗子:
var A = {
name : "A",
}
var B = {
name : "B",
getName : function(){
console.log(this.name);
},
}
B.getName.bind(A)(); //A
B.getName.call(A); //A
B.getName.apply(A); //A
三個輸出的都是A,但是注意看使用 bind() 方法的,他後面多了對括號。
也就是說,區別是,當你希望改變上下文環境之後並非立即執行,而是回撥執行的時候,使用 bind() 方法。而 apply/call 則會立即執行函式。
總結:
apply 、 call 、bind 三者都是用來改變函式的this物件的指向的;
apply 、 call 、bind 三者第一個引數都是this要指向的物件,也就是想指定的上下文;
apply 、 call 、bind 三者都可以利用後續引數傳參;
bind 是返回對應函式,便於稍後呼叫;apply 、call 則是立即呼叫 。
相關文章
- JavaScript進階之模擬call,apply和bindJavaScriptAPP
- this, call, apply 和 bindAPP
- JS中的call、apply、bindJSAPP
- js call,apply,bind總結JSAPP
- js深入之實現call、apply和bindJSAPP
- this、apply、call、bindAPP
- js call、apply、bind的實現JSAPP
- JS中的call、apply、bind方法JSAPP
- js中call、apply、bind函式JSAPP函式
- js中call、apply、bind的用法JSAPP
- [譯] Javascript: call()、apply() 和 bind()JavaScriptAPP
- 【面試題】手寫call、apply、bind面試題APP
- 理解JS中的call、apply、bind方法(********************************************************JSAPP
- 理解JS函式之call,apply,bindJS函式APP
- 回味JS基礎:call apply 與 bindJSAPP
- js中call、apply、bind的區別JSAPP
- js call apply bind簡單的理解JSAPP
- Javascript - apply、call、bindJavaScriptAPP
- js之call,apply和bind的模擬實現JSAPP
- call,apply和bind的區別APP
- 模擬js中的call、apply和bind的實現JSAPP
- 手寫JS函式的call、apply、bindJS函式APP
- apply & call & bind 原始碼APP原始碼
- bind/call/apply 深度理解APP
- 手寫call,apply,bindAPP
- apply,call,bind的用法APP
- call、apply、bind 區別APP
- apply call bind 簡介APP
- 手寫call、apply、bindAPP
- this指向與call,apply,bindAPP
- call apply bind區別APP
- JavaScript-apply、bind、callJavaScriptAPP
- js中call,apply和bind方法的區別和使用場景JSAPP
- JS中改變this的指向 call、apply 和 bind 的區別JSAPP
- 重寫JS中的apply,call,bind,new方法JSAPP
- JS核心系列:淺談 call apply 與 bindJSAPP
- 談談JavaScript中的call、apply和bindJavaScriptAPP
- 【譯】理解this及call,apply和bind的用法APP