posts - 495,comments - 227,trackbacks - 0
          1、關于javascript的apply和call函數

          prototype.js中用了大量的apply和call函數,不注意會造成理解偏差。
          官方解釋:應用某一對象的一個方法,用另一個對象替換當前對象。
          apply與call的區別是第二個參數不同。apply是? 數組或者arguments 對象。而call是逗號隔開的任何類型。

          apply,call方法最讓人混淆的地方也是apply,call的特色。但最好不要濫用。
          能改變調用函數的對象。如下例,函數中用到this關鍵字,這時候this代表的是apply,call函數的第一個參數。

          <script src="prototype1.3.1.js"></script>
          <input type="text" id="myText"? value="input text">
          <script>
          ?? function Obj(){
          ?????? this.value="對象!";
          ?? }
          ?? var value="global 變量";
          ?? function Fun1(){
          ?????? alert(this.value);
          ?? }
          ?? window.Fun1();
          ?? Fun1.apply(window);
          ?? Fun1.apply($('myText'));
          ?? Fun1.apply(new Obj());
          </script>

          2、關于閉包
          prototype.js在Class.create,bind等中用到javascript的閉包特色。但整體上prototype.js對于強大的閉包特性用的不多。大家可以參閱我翻譯的篇文章了解閉包。
          3、讓我比較反感的兩個方法
          (1)
          var Class = {
          ? create: function() {
          ??? return function() {
          ????? this.initialize.apply(this, arguments);
          ??? }
          ? }
          }
          很討厭用別的語言的風格來寫javascript。用這個方法構造自定義類? 并沒有覺得有多方便,減少代碼行數,只會讓人難理解,多定義一個initialize方法。
          其實討厭這條有些牽強,不過修改Object的原型對象就有點過分了。
          (2)Object.prototype.extend
          ? 先不過你取個extend的名字會讓熟悉java的人引起的歧義。修改Object的prototype就說不過去了。不知道作者是怎么考慮的。當你for in循環對象是,麻煩就來了??赡苡腥藭柲鉬or in干嗎。 我一個項目中既用了DWR,也用了prototype.js,dwr返回的javascript對象都多了個exetend屬性,還得特殊處理。
          ? 以前我比較過dojo和prototype.js中繼承的實現,現在我明白個道理。對于javascript這種沒有靜態類型檢查,語法寬松的語言來講,如果你選擇了某個js類庫,那你也必須適應作者寫javascript的風格。prototype.js的作者對extend的使用爐火純青,如果我們不當它只是個屬性拷貝的函數的話,多讀讀prototype.js的代碼是好的。
          4、關于函數的綁定
          ? 類庫提供了Function.prototype.bind? Function.prototype.bindAsEventListener兩個方法。首先我們從概念上解釋一個這兩個方法。
          任何一個函數都可以調用這兩個方法;參數的是javascript對象或網頁上元素對象;返回類型是個函數對象。
          本來我就是個函數,返回還是函數,到這兩個函數有什么不同呢??磳崿F代碼,關鍵還是apply\call函數的代碼。其實這里只是轉化了一下方法調用的對象。

          <script src="prototype1.3.1.js"></script>
          <input type=checkbox id=myChk name="asf" value=1> Test
          <script>
          ??? var CheckboxWatcher = Class.create();
          ??? CheckboxWatcher.prototype = {
          ?????? initialize: function(chkBox, message) {
          ??????????? this.chkBox = $(chkBox);
          ??????????? this.message = message;
          ??????????? this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
          ?????? },
          ?????? showMessage: function(evt) {
          ????????? alert(this.message + ' (' + evt.type + ')');
          ?????? }
          ??? };
          new CheckboxWatcher('myChk','message!!!!');
          //$('myChk').onclick=function(){};
          </script>
          這是 https://compdoc2cn.dev.java.net/ 上舉的例子,個人感覺沒什么意思,反而讓我對bind,bindAsEventListener有些反感。(javascript就是這樣,明明大家都知道的語法,但寫出來的代碼差別確很大)
          看下面代碼:

          <script src="prototype1.3.1.js"></script>
          <input type=checkbox id=myChk name="chk" value=1> Test
          <script>
          function Class(){
          ??? this.name="class";
          }
          Class.prototype.getName=function(){
          ??? alert(this.name);
          }
          var obj=new Class();
          //$('myChk').onclick=obj.getName;
          $('myChk').onclick=obj.getName.bind(obj);
          //$('myChk').onclick=obj.getName.bind($('myChk'));
          </script>

          從上面代碼可以看出bind/bindAsEventListener只是包裝了一下apply/call方法,改變方法的調用對象。如例子,你可以把obj.getName方法轉化成任何對象調用,并且把方法讓表單元素觸發。(bind和bindAsEventListener之間只是返回函數的參數不同)
          這兩個方法也可以用在對象之間的方法重用,實現類似繼承方法的概念??匆韵麓a,其實是比較無聊的。

          <script src="prototype1.3.1.js"></script>
          <script>
          function Class1(name){
          ??? this.name=name;
          }
          Class1.prototype.getName=function(){
          ??? alert(this.name);
          }
          function Class2(name){
          ??? this.name=name;
            this.getName=Class1.prototype.getName.bind(this);
          }
          var obj1=new Class2("yql");
          obj1.getName();
          var obj2=new Object();
          obj2.name="zkj";
          obj2.fun=Class1.prototype.getName.bind(obj2);
          obj2.fun();
          </script>


          我從來沒讀過prototype.js的擴展項目代碼,也不知道bind..的最佳實踐,一起挖掘吧。但你絕對不要把bind/bindAsEventListener從綁定的詞義上來理解,可能會讓你更加迷惑。從apply/call理解本質。應用某一對象的一個方法,用另一個對象替換當前對象。

          5、關于事件的注冊

          <script src="prototype1.3.1.js"></script>
          <input type=checkbox id=myChk name="chk" value=1> Test
          <script>
          Event.observe(myChk, 'click', showMessage, false);
          //$('myChk').onclick=showMessage;
          //$('myChk').onclick=showMessage.bind();
          $('myChk').onclick=showMessage.bind($('myChk'));
          function showMessage() {
          ????? alert(this.value);
          }
          </script>

          執行上面代碼,你就能明白Event.observe與bind/bindAsEventListener之間的區別:
          (1) 顯然Event.observe有限制,只能處理簡單的函數,并函數中不能有this之類的東西。
          (2)Event.observe內部用到addEventListener/attachEvent。能把多個函數加到一個觸發事件(window.onload)。bind是覆蓋。

          6、關于事件監聽最佳實踐
          很顯然prototype.js提供的事件注冊方法不是很完善。那看看dojo的時間注冊吧(中文版),更加復雜,估計很多人像我一樣,對于dojo暫時持觀望態度。
          如果你看過的前篇關于閉包的介紹,可能見過以下代碼。
          看以下代碼前我想表述一個觀點,任何網頁中元素,瀏覽器都會為你創建一個對象()。(我覺得)這些對象與你建立javascript對象區別是它們有事件監聽,會響應鼠標鍵盤的事件。如果你用了以下代碼,那么把事件監聽代碼很好的轉化到你的javascript代碼中。

          function associateObjWithEvent(obj, methodName){
          ??? return (function(e){
          ??????? e = e||window.event;
          ??????? return obj[methodName](e, this);
          ??? });
          }
          function DhtmlObject(elementId){
          ??? var el = getElementWithId(elementId);
          ??? if(el){
          ??????? el.onclick = associateObjWithEvent(this, "doOnClick");
          ??????? el.onmouseover = associateObjWithEvent(this, "doMouseOver");
          ??????? el.onmouseout = associateObjWithEvent(this, "doMouseOut");
          ??? }
          }
          DhtmlObject.prototype.doOnClick = function(event, element){
          ??? ... // doOnClick method body.
          }
          DhtmlObject.prototype.doMouseOver = function(event, element){
          ??? ... // doMouseOver method body.
          }
          DhtmlObject.prototype.doMouseOut = function(event, element){
          ??? ... // doMouseOut method body.
          }

          posted on 2006-12-27 10:11 SIMONE 閱讀(507) 評論(0)  編輯  收藏 所屬分類: JavaScript
          主站蜘蛛池模板: 通山县| 泉州市| 棋牌| 荥经县| 射洪县| 扎鲁特旗| 延庆县| 和平县| 张家川| 邛崃市| 朝阳市| 内黄县| 大邑县| 长宁县| 高台县| 东乡族自治县| 政和县| 德庆县| 阳山县| 衢州市| 莲花县| 方山县| 吴旗县| 中牟县| 新昌县| 鹤庆县| 磐安县| 弥渡县| 闽清县| 通山县| 伊宁县| 大悟县| 漾濞| 鱼台县| 木兰县| 长顺县| 海淀区| 曲沃县| 涿州市| 黑龙江省| 方城县|