老虎美食博客

和老虎一起美食一下吧!

« 在 JavaScript 中如何创建多行字符串(JavaScript Multiline String)JavaScript 获得页面区域大小的代码 »

prototype.js 中的 bind() 函數

prototype.js 中的 bind() 函數

 

看到一篇描述有關 closure 概念的有趣文章:Using Closures To Support Object-Oriented AJAX
作者舉出一個在使用 AJAX時我們常犯的錯誤,並且解釋為什麼這個程式碼有問題:

function User(username, password, div) {
this.username = username;
this.password = password;
this.div = div;
this.retrieve();
}

User.prototype.update = function(req) {
this.div.innerHTML += req.responseText;
}

User.prototype.retrieve = function() {
var myAjax = new Ajax.Request('/users/demo',
{ method:'get',
onComplete:this.update
});
}

錯誤的地方在於 this.update會跑出錯誤因為 this 不是指向 User 這個物件,它其實是XMLHttpRequest。這個很容易看出來程式碼在執行時會有錯誤,因為,那是在 new Ajax.Request(...) 中的程式碼,所以,this 當然是 XMLHttpRequest 而不會是 User。

改進一下成為第二個(錯誤)範例:

User.prototype.retrieve = function() {
var _this = this; // don't overload the meaning of 'this'
var myAjax = new Ajax.Request('/users/demo',
{ method:'get',
onComplete: _this.update
});
}

改成這樣也是錯。這一次會說:this 沒有 div 性質 (在 update() 方法中)。至少,這一次 this 是指向 User 物件了。作者有說到這與JavaScript 的動態本質有關。重點在於:能夠取得一個物件實體的方法並不保證 this 總是參照這個實體物件。(JavaScript 真的很動態,...或者應該說很變態呢...因為它似乎不像傳統的OO語法)。

在JavaScript中,this 會根據它被使用的context(內文)而改變它的意思。要引用到正確的內文,正確的寫法是:

User.prototype.retrieve = function() {
var _this = this; // don't overload the meaning of 'this'
var myAjax = new Ajax.Request('/users/demo',
{ method:'get',
onComplete:function(req) { _this.update(req); }
});
}

真奇怪,

onComplete: _this.update <---- 不行onComplete:function(req) { _this.update(req); } <---- 可以

這一次, onComplete 參照到一個匿名函數,當 Ajax.Request呼叫它時,將會參照到一個User的實體,必且呼叫它的update方法。你看出來了嗎?有沒有被函數包住結果差很多勒。這是因為在JavaScript中的函數與一般語言中所談論的函數本質上是不一樣的。上頭說可以的那句話你可以把它想成是:把物件實體指派給函數的意思。(這與我們一般的觀念:方法指派給物件剛好反過來,JavaScript夠亂了吧。)

作者又提到,這樣做與

User.prototype.retrieve = function() {
var myAjax = new Ajax.Request('/users/demo',
{ method:'get',
onComplete:this.update(req)
});
}

是不一樣的,還是會有錯誤。這當然不一樣,沒了 function() 宣告一切就不一樣了。

最後一個範例使用到 prototype 的 bind()方法來解決這個問題,這樣比較有物件導向的精神。

作法是:

User.prototype.retrieve = function() {
var myAjax = new Ajax.Request('/users/demo',
{ method:'get',
onComplete:this.update.bind(this)
});
}
一堆 this 可能越看越迷糊。有一位回應者給出了下面簡單的作法,根本不用去理會那個 this。

 

User.prototype.retrieve = function() {
var update = function(req) { user.update(req); } // 先定義函數本體,注意那個 user變數
update.user = this; // 再把 this 指派給 user,等一下被callback時,物件實體的參照就不會錯了。

var myAjax = new Ajax.Request(
$(’addFeedResource’).href,
{
method:’delete’,
parameters:’url=’ + feedUrl,
onComplete:update;
}
);
}

這樣可能比較清楚也不會被this給混淆邏輯了吧。

  • 相关文章:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Spirit Build 80605 Code detection by Codefense

Copyright 2007 老虎美食博客. Some Rights Reserved.