<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Open-Source World

    let's learn and study.
    posts - 28, comments - 23, trackbacks - 0, articles - 1
    說起OO,我們首先想到的肯定是抽象,繼承,多態,重載等一系列的名詞。而在JavaScript語言中,因為它是基于對象的(Object-Based),并不是面向對象的(object-oriented),所有它并沒有提供這些能力。它僅僅具有一些面向對象的基本的特征而已(比如您可以使用 new 語句來調用一個構造函數)。
         但在prototype中通過一些巧妙的方式實現了對象的抽象與繼承, 通過使用Object.extend方法,它甚至可以允許我們實現多重繼承.
         下面我們來看Enumerable的each()方法實現:
        
         第一步:
           each: function(iterator) {
           var index = 0;
           try {
             this._each(function(value) {
               try {
                 iterator(value, index++);
               } catch (e) {
                 if (e != $continue) throw e;
               }
             });
           } catch (e) {
             if (e != $break) throw e;
           }
        }
         第二步
         Object.extend(Element.ClassNames.prototype, Enumerable);
        
         我們看到第一步中each方法內部調用到this._each方法,但this._each方法在Enumerable并未做定義,而是將其定義放在Element.ClassNames.prototype中。第二步就是使用Object.extend擴展Element.ClassNames.prototype的內容。整個過程從Java的角度,相當于定義一個抽象類Enumerable,它提供了對枚舉對象的各種迭代操作,但迭代內容的方式卻通過抽象的方法_each()下放給子類做具體實現, 充分實現了抽象與繼承的功能。整個效果還有另一種實現方式是利用Adapter Pattern來實現轉調用,但這已經不是抽象與繼承的范疇了。
        
        上面例子中我們注意到最重要的一步是Object.extend這個方法的調用了, 看這個方法的源代碼我們發現,這僅僅是子類型對父類型的所有property的拷貝,看似簡單,但它卻幫我們豐富了代碼重用的方式,也利于我們用OO的思維觀察一個類型了。另外,關于多態在JS中談是沒有意義的,重載JS默認就支持了,只是在調用父類同名方法里需要通過call方法來完成,但在prototype中并未做這種重載的實現, 這里就不再多做討論了,有興趣的朋友可以交流。
       
        此外,prototype中還提供了Class這個類型,它只包含一個create方法用于創建一個function對象,并提供默認的初始化構造函數initialize。乍看之下,這個方法功能很是簡單,用處不大,我們完全可以通過JS提供的new function()的方式來實現。但其實作者的巧妙就是在于此,它將一個類型(class)的定義跟一個方法(function)的定義以一種顯示編碼的方式來作了區分,很有利于代碼的后期維護,建議使用prototype框架的朋友盡量使用Class.create創建你的自定類型。
       
        最后,我們來關注一下Function.prototype.bind與Function.prototype.bindAsEventListener這兩個方法, 在prototype中許多自定義對象的封裝, 或者我們自定義的對象封裝中都大量使用到了這兩個方法, bind方法主要的功能就是應用某一對象的一個方法,并用另一個對象替換當前對象。bindAsEventListener類似,但它只提供event做為入口參數。它們主要使用了javascript的apply方法與call方法,不明白可以先看我寫的API Document中的Function類中對這兩個方法的定義說明與示例。
        
        接著先來看prototype源代碼中對 Function.prototype.bind 的定義
     
            Function.prototype.bind = function() {
           var __method = this, args = $A(arguments), object = args.shift();
           return function() {
             return __method.apply(object, args.concat($A(arguments)));
           }
        }
        
     bind方法return的是一個function(),在function()函數內部又用_method.apply的方法做一個轉調用。這種封裝其實是把apply的綁定時即運行封裝成調用時才綁定后運行的方式,這樣的一個封裝非常有利于我們實現對象的組件化實現。有寫過的Microsoft的Behavior的朋友知道,Microsoft的支持這個技術,其實就是一種把腳本程序完全從HTML頁面中分離出來的方法,它對頁面元素直接定義行為腳本,在行為腳本中可以以this的引用直接取得元素。而在低版本的瀏覽器不支持apply方法與call方法時候,我們很難以做到這點,常常需要以附加屬性,全局變量等一些方式做中間數據保存與交換,耦合度高,聚合度低,舉個簡單的例子來觀察一下:

       例子: 我們想讓一個的BOTTON元素賦于一些行為" 累計自身被點擊的次數"
       第一種方法是最簡單的,我們直接給這個botton元素添加onclick方法來累加(如下:代碼1)。但這種方式只能應用在一些簡單的前臺腳本上面,如果我們需要寫一個具有大量行為的元素時,比如寫一個Rich Table,我們就希望它最好應該是個組件了。這樣,我我們只要通過一些簡單的定義就可以使它自動具有一系列的行為。
        代碼1: <input  type="button" value="100" onclick="this.value = parseInt(this.value) + 1"/>
        
         第二種方法(代碼2: ) 我們通過一個普通function定義一個類型,初始化這個類型,傳入要產生行為作用的按鈕ID,被指定的按鈕就自動具有" 累計自身被點擊的次數"的功能了,有效的實現了HTML元素與腳本代碼的執。
          
         代碼2:
          <script language="javascript" src="prototype.js"></script>
          <SCRIPT language="javascript">
          window.onload = function(){
           new NonBindClass("btn1");
          } 
          
          var NonBindClass_Current_Element = null;
          function NonBindClass(element){
           this.element = $(element);
           if(!(this.element || false)){ return null;}       
           this.element.attachEvent('onclick',printValue);
           NonBindClass_Current_Element = this.element;
           function printValue(){
            //注意,這里的this并不是發生當前動作的主體或者當前NonBindClass的實例的引用! 所以我通過中間變量或全局變量的方式來取得元素
            NonBindClass_Current_Element.value = parseInt(NonBindClass_Current_Element.value) + 1;
           }
          }
          </SCRIPT>
          <input id="btn1" type="button" value="100"/>      
        但是這里我們看到printValue方法中使用NonBindClass_Current_Element這個全局變量來取得定義元素的對象, 但這種全局變量常常讓人無比的頭痛! 而且, 這時候如果需要給另一個按鈕btn3也添加同樣行為,那么全局變量NonBindClass_Current_Element會被重新指向到btn3,而對于btn1的點擊事件也會隨之作用到btn3,使得我們無法達到目的。當然,我們可以通過其它的方式來達到目的,比如讓printValue方法內部可以直接引用到指定的對象:  一種辦法就是傳入參數,但這種方法在做attachEvent方法綁定時會直接做調用到printValue方法! 還有一種辦法 就是使用prototype的bind方法,我們可以給printValue綁定任意的對象,bind(this)或者bind(this.element)都可以達到目的,具體請看 代碼3:
        代碼3:
         <script language="javascript" src="prototype.js"></script>
         <SCRIPT language="javascript">
         window.onload = function(){
          new BindClass("btn1");
          new BindClass("btn2"); 
         } 
         
         function BindClass(element){
          this.element = $(element);
          if(!(this.element || false)){ return null;}       
          this.element.attachEvent('onclick',printValue.bind(this.element));
          function printValue(obj){
           this.value = parseInt(this.value) + 1;
          }
         }
         </SCRIPT>
         <input id="btn1" type="button" value="100"/>  
         <input id="btn2" type="button" value="200"/>  
         代碼更加精簡,內聚度也高,并且支持給多個不同的元素賦予同樣行為。
         Function.prototype.bindAsEventListener的功能類似,差別在于它只傳入固定的一個event參數,用于事件后期運行時綁定調用.

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 久久精品九九亚洲精品| 亚洲AV无码一区二区三区久久精品 | 亚洲国产精品激情在线观看| 亚洲成AⅤ人影院在线观看| baoyu777永久免费视频| 久久精品国产亚洲av麻豆图片| 又粗又黄又猛又爽大片免费| 日本免费人成网ww555在线| 亚洲一区二区无码偷拍| 亚洲日本韩国在线| 91精品国产免费久久久久久青草| 国产精品亚洲专区无码唯爱网 | 日韩亚洲不卡在线视频中文字幕在线观看| 国产又黄又爽又猛的免费视频播放 | 亚洲午夜无码久久久久软件| 久久亚洲AV无码西西人体| 青娱分类视频精品免费2| 一级毛片高清免费播放| 亚洲欧好州第一的日产suv| 亚洲国产精品一区第二页 | 亚洲色无码一区二区三区| 久久电影网午夜鲁丝片免费| 中文日本免费高清| 亚洲日韩国产一区二区三区在线| 日韩一卡2卡3卡4卡新区亚洲 | 国产亚洲成AV人片在线观黄桃 | 亚洲色大成网站www永久| 亚洲精品无码日韩国产不卡?V| 五月婷婷在线免费观看| a级毛片黄免费a级毛片| AV激情亚洲男人的天堂国语| 亚洲国产成人精品久久| 亚洲AV无码一区二区三区DV | 国产精品酒店视频免费看| 亚洲精品视频在线免费| 成人无码a级毛片免费| 一级毛片免费观看不收费| 色欲aⅴ亚洲情无码AV| 亚洲欧洲日本在线观看| 99人中文字幕亚洲区| 久久被窝电影亚洲爽爽爽|