原文:http://dojotoolkit.org/documentation/tutorials/1.7/hitch/
在dojo工具包中,dojo/_base/lang模塊對Javascript原生方法進行了包裝或增強,提供了不少相當有用的方法。本文將介紹Javascript中的函數對象(Function)的基礎知識,以及如何使用dojo.hitch綁定函數的上下文,另外還將介紹如何使用dojo.partial爲函數綁定特定參數等實用技術。
在講解dojo.hitch和dojo.partial的用法之前,要先明白它們能解決什麼問題。Javascript編程中最常聽到的問題之一:this是什麼?對面向對象編程來說,方法內部的this就是聲明該方法的對象,非常簡單!而對於Javascript,答案可不那麼簡單了。爲求知其然並知其所以然,有必要了解Javascript中的函數上下文。
Javascript函數上下文
每當一個函數被調用時,Javascript會創建一個對應的上下文。上下文創建步驟如下:
- 創建argument對象;
- 創建函數的scope對象;
- 初始化函數的局部變量;
- 創建this屬性;
其中this指向的是正在調用該函數的對象。理解這一點對於理解Javascript中的函數運行非常關鍵,因爲Javascript中函數的上下文是在函數被調用的時候才確定的。
這裏舉一個例子:有一個object,這個object其中一個方法被當做多個HTML節點的點擊事件的處理函數。下面是對應的代碼。
[javascript] view plaincopy
1. var myObject = {
2. foo: "bar",
3. myHandler: function(evt){
4. // this is very contrived but will do.
5. alert("The value of 'foo' is " + this.foo);
6. }
7. };
8.
9. // later on in the script:
10. dojo.query(".myNodes").forEach(function(node){
11. node.onclick = myObject.myHandler;
12. });
請看對應的Demo(http://dojotoolkit.org/documentation/tutorials/1.7/hitch/demo/demo.html)
當這些class爲“myNodes”的button被點擊時,你可能會認爲瀏覽器會彈出“The value of'foo' is bar”的消息,然而由於上面的myObject.myHandler綁定了節點的點擊事件,導致瀏覽器彈出了“The value of 'foo' is undefined”。這是因爲myObject.myHandler被作爲節點的上下文執行,並非被myObject自己執行。換句話說,Javascript解釋器認爲當前的this指向了被點擊的節點而非myObject。
使用apply、call指定函數運行上下文
Javascript爲函數對象提供了apply與call方法,用於切換函數的運行時上下文。兩種方法都可以通過傳入運行時上下文,從而顯式地指定this屬性的引用。舉例來說,我們希望上例中的節點被點擊時,觸發的myObject.myHandler的上下文爲myObject。這裏使用call方法爲例:
[javascript] view plaincopy
1. dojo.query(".myNodes").forEach(function(node){
2. node.onclick = function(evt){
3. return myObject.myHandler.call(myObject, evt);
4. };
5. });
請看對應的Demo(http://dojotoolkit.org/documentation/tutorials/1.7/hitch/demo/call.html)
理解了Javascript函數的上下文基礎後,來看看dojo如何使用dojo.hitch來簡化這一過程。
使用dojo.hitch綁定函數運行時上下文
Dojo.hitch是dojo提供的一個用來簡化函數運行時上下文綁定的函數。簡單來說dojo.hitch創建了一個綁定了上下文的新函數,用戶可以不用擔心心運行時的上下文變化會對函數產生影響。使用dojo.hitch也十分簡單:
[javascript] view plaincopy
1. var foo = "bar"
2. var myFunction = function(){
3. return this.foo;
4. };
5. var myObject = { foo: "baz" };
6. // later on in your application
7. var boundFunction = dojo.hitch(myObject, myFunction);
8. // the first value will be "bar", the second will be "baz";
9. // the third will still be "bar".
10. myFunction(); // "bar"
11. boundFunction(); // "baz"
12. myFunction(); // "bar"
對應Demo(http://dojotoolkit.org/documentation/tutorials/1.7/hitch/demo/hitch.html)
可以看到,無論外部運行時上下文如何變化,dojo.hitch保證函數myFunction的上下文對象始終是myObject。
arguments對象
還記得之前Javascript被調用時創建上下文的步驟嗎?首先創建的就是arguments對象,arguments對象是一個函數的參數數組,以參數的傳入順序排列該數組內元素。
當函數定義完成後,其函數簽名就被固定下來。我們就不能增加或者刪除非匿名的函數參數。有時候這限制了函數調用的靈活性,我們不得不重寫新的函數來應付參數列表的變更,而dojo.partial方法打破了這個限制。
使用dojo.partial控制參數列表
首先看下面的例子(取自dojo/data模塊),參數列表中有4個參數:
[javascript] view plaincopy
1. var putValue = function(store, item, attr, value){
2. return store.setValue(item, attr, value);
3. }
然而後來在應用需要與putValue有相似的功能但參數列表不同的函數,如下所示:
[javascript] view plaincopy
1. //已聲明的myStore對象
2. var myStore = new dojo.data.ItemWriteStore({…});
3. someObject.setValueHandler = function(item, attr, value){
4. myStore.setValue(item, attr, value);
5. };
dojo.partial是一個返回值爲函數的函數,可以用預定義的值鎖定函數的前幾個參數。我們可以使用dojo.partial來避免someObject.setValueHandler的重複定義,代碼如下:
[html] view plaincopy
1. var putValue = function(store, item, attr, value){
2. return store.setValue(item, attr, value);
3. }
4. ...
5. var myStore = new dojo.data.ItemWriteStore({...});
6. //dojo.partial返回了首個參數爲myStore的putValue函數
7. someObject.setValueHandler = dojo.partial(putValue, myStore);
8.
9. //等同於運行putValue(myStore, someItem, “foo”, “bar”)
10. someObject.setValueHandler(someItem, "foo", "bar");
這裏需要注意的是,dojo.partial並不鎖定函數的運行時上下文。
同時綁定運行時上下文和鎖定參數
如果我們希望同時綁定運行時上下文和鎖定參數,dojo.hitch本身就可以完成這兩個功能。dojo.hitch的頭兩個參數指的是要綁定的運行時上下文與對應函數,這兩個參數後面可接上任意多個作爲第二個參數代表的對應函數的鎖定參數,代碼如下:
[html] view plaincopy
1. someObject.setValueHandler = dojo.hitch(someObject, putValue, myStore);
2.
3. // putValue的首個參數被鎖定爲myStore,並且putValue中的this參數(如果有的話)指向someObject
4. someObject.setValueHandler(someItem, "foo", "bar");
總結
在本教程中,首先闡述了Javascript運行時上下文的基礎,然後介紹如何使用dojo.hitch方法固定函數的運行時上下文,又瞭解了使用固定值鎖定參數列表的方法-dojo.partial,最後介紹了使用dojo.hitch同時實現這兩個功能。
Dojo.hitch在事件驅動的編程模型中十分有效,用戶無需關心函數運行時上下文的變更,降低代碼的耦合性。