今天來分析下extend方法在各種js框架下的設計。這個函數的功能基本都是實現對象的拷貝功能,即將一個對象的所有屬屬性拷貝到另外一個對象上去,這個函數使用的頻率也很高,如果我們要將一個類的所有方法拷貝到另外方法上去,使用這個方法很方便的。
 
        1)在百度tangram js 框架中的實現,
 
        
          baidu.extend = 
        
 
        
          baidu.object.extend = function (target, source) { 
        
 
        
              for (var p in source) { 
        
 
        
                  if (source.hasOwnProperty(p)) { 
        
 
        
                      target[p] = source[p]; 
        
 
        
                  } 
        
 
        
              } 
        
 
        
               
        
 
        
              return target; 
        
 
        
          }; 
        
 
        
          僅有2個參數,extend(target,source),第一個參數是目標對象,第二個參數是原對象 ,對原對象中的每個屬性進行判斷,如果是,那么將他拷貝到目標的對象上去。 
        
 
         
         
         
 
        2)在jquery 中的實現:
 
        
          jQuery.extend = jQuery.fn.extend = function() { 
        
 
         
          var options, name, src, copy, copyIsArray, clone, 
        
 
         
          target = arguments[0] || {}, 
        
 
         
          i = 1, 
        
 
         
          length = arguments.length, 
        
 
         
          deep = false; 
        
 
         
         
          //如果第一個值為bool值,那么就將第二個參數作為目標參數,同時目標參數從2開始計數 
        
 
         
          if ( typeof target === "boolean" ) { 
        
 
         
          deep = target; 
        
 
         
          target = arguments[1] || {}; 
        
 
         
          // skip the boolean and the target 
        
 
         
          i = 2; 
        
 
         
          } 
        
 
         
         
          // 當目標參數不是object 或者不是函數的時候,設置成object類型的 
        
 
         
          if ( typeof target !== "object" && !jQuery.isFunction(target) ) { 
        
 
         
          target = {}; 
        
 
         
         
         
          } 
        
 
         
         
          //如果extend只有一個函數的時候,那么將跳出后面的操作 
        
 
         
          if ( length === i ) { 
        
 
         
          target = this; 
        
 
         
          --i; 
        
 
         
          } 
        
 
         
         
          for ( ; i < length; i++ ) { 
        
 
         
          // 僅處理不是 null/undefined values 
        
 
         
          if ( (options = arguments[ i ]) != null ) { 
        
 
         
          // 擴展options對象 
        
 
         
          for ( name in options ) { 
        
 
         
          src = target[ name ]; 
        
 
         
          copy = options[ name ]; 
        
 
         
         
          // 如果目標對象和要拷貝的對象是恆相等的話,那就執行下一個循環。 
        
 
         
          if ( target === copy ) { 
        
 
         
          continue; 
        
 
         
          } 
        
 
         
         
         
         
          // 如果我們拷貝的對象是一個對象或者數組的話 
        
 
         
          if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { 
        
 
         
          if ( copyIsArray ) { 
        
 
         
          copyIsArray = false; 
        
 
         
          clone = src && jQuery.isArray(src) ? src : []; 
        
 
         
         
          } else { 
        
 
         
          clone = src && jQuery.isPlainObject(src) ? src : {}; 
        
 
         
          } 
        
 
         
         
          //不刪除目標對象,將目標對象和原對象重新拷貝一份出來。  
        
 
         
          target[ name ] = jQuery.extend( deep, clone, copy ); 
        
 
         
         
          // 如果options[name]的不為空,那么將拷貝到目標對象上去。 
        
 
         
          } else if ( copy !== undefined ) { 
        
 
         
          target[ name ] = copy; 
        
 
         
          } 
        
 
         
          } 
        
 
         
          } 
        
 
         
         
         
          } 
        
 
         
         
          // 返回修改的目標對象 
        
 
         
          return target; 
        
 
        }; 
 
        jquery的實現原理和tangram差不多,也是講原對象的屬性分別拷貝到目標對象上去,不過jq可以接受的參數比tangram要多,他可以接受無限和參數,如果第一個參數為true的話,將執行深度拷貝,將原對象和目標對象中的某些屬性值合並起來。
 
         3)protype.js的實現方式
 
        
            function extend(destination, source) { 
        
 
        
              for (var property in source) 
        
 
        
                destination[property] = source[property]; 
        
 
        
              return destination; 
        
 
          } 
 
        也是遍歷原 對象的各種屬性,然后將他拷貝到目標對象上去。實現的方式和tangram類似。
 
         4)dojo的實現
 
         
          dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){ 
        
 
         
          // summary: 
        
 
         
          // 
          Adds all properties and methods of props to constructor's 
        
 
         
          // 
          prototype, making them available to all instances created with 
        
 
         
          // 
          constructor. 
        
 
         
          for(var i=1, l=arguments.length; i<l; i++){ 
        
 
         
          d._mixin(constructor.prototype, arguments[i]); 
        
 
         
          } 
        
 
         
          return constructor; // Object 
        
 
         } 
 
         
 
         
          var extraNames, extraLen, empty = {}; 
        
 
         
          for(var i in {toString: 1}){ extraNames = []; break; } 
        
 
         
          dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf", 
        
 
         
          "propertyIsEnumerable", "toLocaleString", "toString", "constructor"]; 
        
 
         
          extraLen = extraNames.length; 
        
 
         
         
          dojo._mixin = function(/*Object*/ target, /*Object*/ source){ 
        
 
         
          // summary: 
        
 
         
          // 
          Adds all properties and methods of source to target. This addition 
        
 
         
          // 
          is "prototype extension safe", so that instances of objects 
        
 
         
          // 
          will not pass along prototype defaults. 
        
 
         
          var name, s, i; 
        
 
         
          for(name in source){ 
        
 
         
          // the "tobj" condition avoid copying properties in "source" 
        
 
         
          // inherited from Object.prototype.  For example, if target has a custom 
        
 
         
          // toString() method, don't overwrite it with the toString() method 
        
 
         
          // that source inherited from Object.prototype 
        
 
         
          s = source[name]; 
        
 
         
          //fixed by yupeng 判斷元素是否是對象的屬性 
        
 
         
          if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ 
        
 
         
          target[name] = s; 
        
 
         
          } 
        
 
         
          } 
        
 
         
          // IE doesn't recognize some custom functions in for..in 
        
 
         
          if(extraLen && source){ 
        
 
         
          for(i = 0; i < extraLen; ++i){ 
        
 
         
          name = extraNames[i]; 
        
 
         
          s = source[name]; 
        
 
         
          if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){ 
        
 
         
          target[name] = s; 
        
 
         
          } 
        
 
         
          } 
        
 
         
          } 
        
 
         
          return target; // Object 
        
 
         } 
 
         dojo首先會封裝一個_mixin方法,該方法起到的作用其實就是extend該起到的作用,然后再背部調用_mixin()方法,封裝的extend方法可以接受多個參數,同時將原對象的每個屬性都拷貝到目標對象的原型方法上。 
 
        技巧(extend方法的妙用):
 
        1)實現組件參數的靈活配置,我們在寫組件的時候,可以使用一些默認的配置參數,但是如果用戶想定制一些特殊的樣式的話,可以使用extend方法
 
        例如在寫jq插件的時候
 
        
          (function($) {  
        
 
        $.fn.xxxx= function(options) {
 
         
          var defaults = { 
        
 
         
          a: false, 
        
 
         
          b: {}, 
        
 
         
          c: false, 
        
 
         
          b: false 
        
 
         
          }; 
        
 
         var params = $.extend({}, defaults, options || {}); 
 
         //接下來對函數進行處理。 
 
        } 
 
        })(jquery) 
 
        2)實現類方法的拷貝。