天天看點

javascript中的深複制方法一:jQuery中的extend方法

extend文法

jQuery中的extend方法寫插件常用到的方法:

jQuery.extend([deep], target, object1, [objectN])
           

概述

用一個或多個其他對象來擴充一個對象,傳回被擴充的對象。

如果不指定target,則給jQuery命名空間本身進行擴充。這有助于插件作者為jQuery增加新方法。 如果第一個參數設定為true,則jQuery傳回一個深層次的副本,遞歸地複制找到的任何對象。否則的話,副本會與原對象共享結構。 未定義的屬性将不會被複制,然而從對象的原型繼承的屬性将會被複制。

參數

[deep],target,object1,[objectN]

Boolean,Object,Object,Object

注意:

deep參數隻有兩種情況:true(深複制)或者無(淺複制)。

deep參數為true的時候,若參數是兩個或者兩個以上,則是深複制。若參數是一個則是添加新函數。

沒有deep參數的時候,若參數是一個的時候,功能是添加新函數。若參數是兩個或者兩個以上的時候是淺複制。

由jQuery.extend源碼可知,deep參數預設是false,但是在調用extend的時候如果不是深複制則不能将false傳給deep,否則會将false當成target。

特别注意:

為了減少麻煩,使用jQuery.extend實作淺複制的時候,不要使用jQuery.extend(false, object1, object2, [objectN])的形式,

因為此時目标參數target不是object1,extend函數的傳回值不是object1,而是将第一個參數false轉換成對象{},并且作為目标參數,

是以extend對object1不會進行修改。jQuery.extend(false, object1, object2, [objectN])的形式等效于jQuery.extend({}, object1, object2, [objectN]),target={}。

deep:如果設為true,則遞歸合并

target:待修改對象。

object1:待合并到第一個對象的對象。

objectN:待合并到第一個對象的對象。

target,[object1],[objectN]

Object,Object,Object

注意:

這裡是淺複制

target:一個對象,如果附加的對象被傳遞給這個方法将那麼它将接收新的屬性,如果它是唯一的參數将擴充jQuery的命名空間。

object1:待合并到第一個對象的對象。

objectN:待合并到第一個對象的對象。

能實作的功能

1:将兩個或多個對象的内容合并到第一個對象

jQuery.extend( target [, object1 ] [, objectN ] )
           
         extend方法需要至少傳入一個參數,第一個必需,後面的都是可選參數。若傳給extend是兩個或兩個以上的參數都是對象類型,那麼就會把後面所有對象的内容合并給target(第一個對象)上。

2:為jQuery添加新函數

jQuery.extend(target)
           
         如果隻有一個參數,在這種情況下,jQuery對象本身被預設為目标對象。這樣,我們可以在jQuery的命名空間下添加新的功能。這對于插件開發者希望向 jQuery 中添加新函數時是很有用的。

jQuery源碼解釋

// 為與源碼的下标對應上,我們把第一個參數稱為`第0個參數`,依次類推
jQuery.extend = jQuery.fn.extend = function() {
 var options, name, src, copy, copyIsArray, clone,
 target = arguments[0] || {}, // 預設第0個參數為目标參數
 i = 1, // i表示從第幾個參數凱斯想目标參數進行合并,預設從第1個參數開始向第0個參數進行合并
 length = arguments.length,
 deep = false; // 預設為淺度拷貝
 
 // 判斷第0個參數的類型,若第0個參數是boolean類型,則擷取其為true還是false
 // 同時将第1個參數作為目标參數,i從目前目标參數的下一個
 // Handle a deep copy situation
 if ( typeof target === "boolean" ) {
 deep = target;
 
 // Skip the boolean and the target
 target = arguments[ i ] || {};
 i++;
 }
 
 // 判斷目标參數的類型,若目标參數既不是object類型,也不是function類型,則為目标參數重新指派 
 // Handle case when target is a string or something (possible in deep copy)
 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
 target = {};
 }
 
 // 若目标參數後面沒有參數了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
 // 則目标參數即為jQuery本身,而target表示的參數不再為目标參數
 // Extend jQuery itself if only one argument is passed
 if ( i === length ) {
 target = this;
 i--;
 }
 
 // 從第i個參數開始
 for ( ; i < length; i++ ) {
 // 擷取第i個參數,且該參數不為null和undefind,在js中null和undefined,如果不區分類型,是相等的,null==undefined為true,
 // 是以可以用null來同時過濾掉null和undefind
 // 比如$.extend(target, {}, null);中的第2個參數null是不參與合并的
 // Only deal with non-null/undefined values
 if ( (options = arguments[ i ]) != null ) {
  
 // 使用for~in擷取該參數中所有的字段
 // Extend the base object
 for ( name in options ) {
 src = target[ name ]; // 目标參數中name字段的值
 copy = options[ name ]; // 目前參數中name字段的值
 
 // 若參數中字段的值就是目标參數,停止指派,進行下一個字段的指派
 // 這是為了防止無限的循環嵌套,我們把這個稱為,在下面進行比較詳細的講解
 // Prevent never-ending loop
 if ( target === copy ) {
  continue;
 }
 
 // 若deep為true,且目前參數中name字段的值存在且為object類型或Array類型,則進行深度指派
 // Recurse if we're merging plain objects or arrays
 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  // 若目前參數中name字段的值為Array類型
  // 判斷目标參數中name字段的值是否存在,若存在則使用原來的,否則進行初始化
  if ( copyIsArray ) {
  copyIsArray = false;
  clone = src && jQuery.isArray(src) ? src : [];
 
  } else {
  // 若原對象存在,則直接進行使用,而不是建立
  clone = src && jQuery.isPlainObject(src) ? src : {};
  }
 
  // 遞歸處理,此處為2.2
  // Never move original objects, clone them  
  target[ name ] = jQuery.extend( deep, clone, copy );
 
 // deep為false,則表示淺度拷貝,直接進行指派
 // 若copy是簡單的類型且存在值,則直接進行指派
 // Don't bring in undefined values
 } else if ( copy !== undefined ) {
  // 若原對象存在name屬性,則直接覆寫掉;若不存在,則建立新的屬性
  target[ name ] = copy;
 }
 }
 }
 }
 
 // 傳回修改後的目标參數
 // Return the modified object
 return target;
};