Prototype的bind方法常常把許多學(xué)習(xí)它的人弄得糊糊涂涂,google和baidu一番后還是一塌胡涂!本人也如此;本人覺得它是個從“謎人”到“迷人”的方法。此文將發(fā)表個人對此方法的理解,希望能幫助大家成功渡“謎”,到達(dá)“迷人”的彼岸!
<html>
<head>
<script src="prototype.js"></script> //@7
<script type="text/javascript">
/**********************************
*
* 實現(xiàn)渲染一個帶有"上一頁"和"下一頁"的組件,點擊"上一頁",當(dāng)前頁減1,點擊"下一頁"當(dāng)前頁加1
*
*/
function PagesSystem(container){
this.currentPage = 10; //當(dāng)前頁
this.pageSysDiv = document.getElementById(container); //容器
this.init = function() { //將組件畫出來
this.createPrePage();
this.createNextPage();
};
this.changePage = function(evtObj) { //根據(jù)點擊后傳過來的參數(shù)決定是加1或是減1
if(evtObj == "next") {
this.currentPage += 1;
alert("你已執(zhí)行將當(dāng)前頁加1,現(xiàn)在當(dāng)前頁是:" + this.currentPage);
}else if(evtObj == "pre"){
//此處不作if(this.currentPage ==1) return;限制為了體現(xiàn)當(dāng)傳入的參數(shù)為"pre"時,下面的alert()一定會執(zhí)行
this.currentPage -= 1;
alert("你已執(zhí)行將當(dāng)前頁減1,現(xiàn)在當(dāng)前頁是:" + this.currentPage);
}
};
this.createPrePage = function() {//創(chuàng)建上一頁組件
var _span = document.createElement("SPAN");
_span.style.cssText = "margin-left:16px";
var _a = document.createElement("A");
_a.href = "#";
_a.onclick = this.changePage; //@1 當(dāng)點擊此("上一頁")銨鈕時執(zhí)行
_a.innerText = "上一頁";
_span.appendChild(_a);
this.pageSysDiv.appendChild(_span);
};
this.createNextPage = function() {//創(chuàng)建下一頁組件
var _span = document.createElement("SPAN");
_span.style.cssText = "margin-left:16px";
var _a = document.createElement("A");
_a.href = "#";
_a.onclick = this.changePage; //@2 當(dāng)點擊此("下一頁")銨鈕時執(zhí)行
_a.innerText = "下一頁";
_span.appendChild(_a);
this.pageSysDiv.appendChild(_span);
};
this.init(); //執(zhí)行初始化
}
function testUse(msg){//@3在提出問題環(huán)節(jié)用到
alert(msg);
}
window.onload = function() {
var ps = new PagesSystem("pageDiv");
}
</script>
</head>
<body>
<div id="pageDiv"></div>
</body>
</html>
二、分析代碼,提出問題,解決問題
1、無法傳遞參數(shù)問題。
你細(xì)看@1和@2處,當(dāng)前的代碼實現(xiàn)是無法把"pre"和"next"參數(shù)傳遞過去,于是,當(dāng)你運行例子,點擊上一頁或下一頁,都是沒信息alert出來的!
這種情況,是很常見的。那么,如何實現(xiàn)將參數(shù)傳過去。
將@1處代碼修改如下:
_a.onclick = function(){ //@1 當(dāng)點擊此("上一頁")銨鈕時執(zhí)行
testUse("pre"); //參看@3
this.changePage("pre");
}
這樣創(chuàng)建一個匿名函數(shù)賦予_a.onclick,也就是當(dāng)_a對象的onclick事件觸發(fā)后將執(zhí)行此匿名函數(shù),而匿名函數(shù)將幫忙調(diào)用testUse("pre")和this.changePage("pre")兩個方法,
從而達(dá)成傳遞參數(shù)。
修改代碼,運行例子后點擊上一頁后會顯示如下兩個信息,一個是testUse中輸出的信息,證明了實現(xiàn)參數(shù)傳遞,另一個卻是運行錯誤提示。

這是執(zhí)行this.changePage("pre")方法拋出來的。它并沒像我們預(yù)期想的運行。
從提示獲到的信息是,對象不支持此屬性或方法(如果瀏覽器報的是中文提示就可以看到“對象不支持此方法或?qū)傩?#8221;的提示)
回頭看this.changePage("pre")方法,很明顯this是錯誤提示中所指的對象,在本應(yīng)用中指PagesSystem對象指針的引用,在應(yīng)用中確實是聲明了this.changePage("pre")方法,但為什么說沒此方法呢????
2、在問題1中,我們已成功解決傳遞參數(shù),但PagesSystem對象的changePage方法被誰偷了???
再將剛才的代碼修改如:
_a.onclick = function(){ //@1 當(dāng)點擊此("上一頁")銨鈕時執(zhí)行
testUse("pre"); //參看@3
alert(this.tagName);
this.changePage("pre");
}
再運行例子,你會發(fā)現(xiàn)輸出this.tagName的值為 A, 它就是_a對象。噢,我的天啊。怎么會這樣???
哈哈..._a對象就是<a href=""/></a>這個html 元素對象,這里是“上一頁”銨鈕對象,原型中哪來changePage方法啊,所以報錯!!!
你可以這樣理解,看如下代碼:
function PagesSystem(container){//此應(yīng)用中的PagesSystem對象,changePage方法的上下文對象,也可以稱為歸屬者。
//...省略其它代碼
this.changePage = function(evtObj) { //根據(jù)點擊后傳過來的參數(shù)決定是加1或是減1
if(evtObj == "next") {
this.currentPage += 1;
alert("你已執(zhí)行將當(dāng)前頁加1,現(xiàn)在當(dāng)前頁是:" + this.currentPage);
}else if(evtObj == "pre"){
//此處不作if(this.currentPage ==1) return;限制為了體現(xiàn)當(dāng)傳入的參數(shù)為"pre"時,下面的alert()一定會執(zhí)行
this.currentPage -= 1;
alert("你已執(zhí)行將當(dāng)前頁減1,現(xiàn)在當(dāng)前頁是:" + this.currentPage);
}
};
//...省略其它代碼
}
這樣的代碼,你很容易看出this是指PagesSystem, 那么我們繼續(xù)往下看
假設(shè) A對象的原型如下:
function A() {//@4
//...
this.onclick;
this.doClick = function() { //點擊
this.onclick();//執(zhí)行
}
//...
}
當(dāng)你在PagesSystem方法中
_a.onclick = function(){ //@1 當(dāng)點擊此("上一頁")銨鈕時執(zhí)行
testUse("pre"); //參看@3
alert(this.tagName);
this.changePage("pre");
}
寫上這樣的代碼后,你可以離譜認(rèn)為@4的代碼的模樣是如下:
function A() {//@4
//...
this.onclick = function(){ //@1 當(dāng)點擊此("上一頁")銨鈕時執(zhí)行
testUse("pre"); //參看@3
alert(this.tagName); //@5
this.changePage("pre"); //@6
};
this.doClick = function() { //點擊
this.onclick();//執(zhí)行
}
//...
}
呵呵。。如果這樣看的話,@5,@6中的this當(dāng)然是指a對象,沒異義。那當(dāng)然是沒changePage方法。
3、那么如何解決這問題呢??
很幸運,prototype.js中的bind方法就可以解決這樣的問題,它還解決我們上面提的傳參數(shù)問題。
看bind大俠帥樣:
bind: function() {
if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
var __method = this, args = $A(arguments), object = args.shift();
return function() {
return __method.apply(object, args.concat($A(arguments)));
}
}
bind方法中的this就是bind方法的所屬者(上下文)如: f.bind(),f是一個聲明了的方法,那么bind 方法里的this就是f
再細(xì)看,bind方法其實做的工作是返回一個匿名函數(shù),此匿名函數(shù)幫忙執(zhí)行this所指的方法(bind方法的所屬者),如果你有如下代碼
function f(msg) {
this.functionName = "f method";
alert(msg);
alert(this.functionName);
}
button.onclick = f.bind(this, msg); //這里的this指f, 在bind方法中用object = args.shift()獲得,這樣的話,當(dāng)點擊button后執(zhí)行f方法, f方法中的this就不會無故被 button代替。^_^不然,會報錯的啊,button哪來functionName,呵呵...
它既解決將msg參數(shù)傳過去,同時將f綁定到button環(huán)境下,bind方法得名可能就是這意義吧。至于如何實現(xiàn)將f綁定,靠的就是apply方法。
apply謎人色彩就由你們自行去揭開啦!
介紹了bind大俠給大家,我的例子就麻煩你們自己調(diào)通它啦。謝了。。
歡迎交流指正。
備注: 如需轉(zhuǎn)載本文,請注明出處
posted on 2008-05-08 22:37
Sonny Li 閱讀(1934)
評論(6) 編輯 收藏 所屬分類:
Prototype學(xué)習(xí)志