jquey.extend深拷贝

来源:互联网 发布:sql字符串截取 汉字 编辑:程序博客网 时间:2024/06/07 06:05

大家如果用过JQuery 的 extend 函数, 一定对 extend 函数 有一定了解。

但是 extend 的深复制也不是 完美, 下面通过 一个例子 与 JQuery 源码  进行分析:

 使用extend时,如果第一个参数传入的是true,则表示需要进行“深拷贝”。但是这是个不完全的深复制,见下面例子:


[javascript] view plain copy
 print?
  1. function Obj(){  
  2.     this.a = 1;  
  3. }  
  4.   
  5. var obj = new Obj();  
  6.   
  7. var tobeCloned = {o:obj};  
  8.   
  9. var result  = $.extend(true,{},tobeCloned);  
  10.   
  11. tobeCloned.o.a = 2;  
  12.   
  13. console.log(result.o.a);//输出是什么呢?  


按照一般的深复制理解,结果输出 应该为 1,但是实际结果却为 2 



让我们去看看JQuery 源代码就明白了:


请看jquery.extend函数的注释版源码(版本为1.7)


JQuery 源代码:

[javascript] view plain copy
 print?
  1. jQuery.extend = jQuery.fn.extend = function() {  
  2.   
  3.     var options, name, src, copy, copyIsArray, clone,  
  4.         target = arguments[0] || {},  
  5.         i = 1,  
  6.         length = arguments.length,  
  7.         deep = false;  
  8.     /* 
  9.     变量 options:指向某个源对象。 
  10.     变量 name:表示某个源对象的某个属性名。 
  11.     变量 src:表示目标对象的某个属性的原始值。 
  12.     变量 copy:表示某个源对象的某个属性的值。 
  13.     变量 copyIsArray:指示变量 copy 是否是数组。 
  14.     变量 clone:表示深度复制时原始值的修正值。 
  15.     变量 target:指向目标对象,申明时先临时用第一个参数值。 
  16.     变量 i:表示源对象的起始下标,申明时先临时用第二个参数值。 
  17.     变量 length:表示参数的个数,用于修正变量 target。 
  18.     变量 deep:指示是否执行深度复制,默认为 false。 
  19.  
  20.     ps:源对象指的是把自己的值付给别人的对象;目标对象指的是被源对象赋值的对象 
  21.     */  
  22.   
  23.     // 如果第一个参数传入的是布尔值  
  24.     if ( typeof target === "boolean" ) {  
  25.         deep = target;//设置deep变量,确定是深拷贝还是浅拷贝  
  26.         target = arguments[1] || {};//将目标对象设为第二个参数值。  
  27.         i = 2;//源对象的起始下标设为2(即从第三个参数开始算源对象)  
  28.     }  
  29.   
  30.     // Handle case when target is a string or something (possible in deep copy)  
  31.     //嗯,原英文解释的很清楚  
  32.     if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  
  33.         target = {};  
  34.     }  
  35.   
  36.     // 如果没有目标对象,那么目标对象就是jquery对象  
  37.     if ( length === i ) {  
  38.         target = this;  
  39.         --i;  
  40.     }  
  41.   
  42.     拷贝的核心部分代码  
  43.     for ( ; i < length; i++ ) {//遍历源对象  
  44.         // Only deal with non-null/undefined values  
  45.         if ( (options = arguments[ i ]) != null ) {//options就是源对象  
  46.             // Extend the base object  
  47.             for ( name in options ) {//遍历源对象的属性名  
  48.                 src = target[ name ];//获取目标对象上,属性名对应的属性  
  49.                 copy = options[ name ];//获取源对象上,属性名对应的属性  
  50.   
  51.                 // 如果复制值copy 与目标对象target相等,  
  52.                 //为了避免深度遍历时死循环,因此不会覆盖目标对象的同名属性。  
  53.                 if ( target === copy ) {  
  54.                     continue;  
  55.                 }  
  56.   
  57.                 //递归地将源对象上的属性值合并到目标对象上  
  58.                 //如果是深拷贝,且待拷贝的对象存在,且是普通对象或是数组  
  59.                 //这一个判断条件非常关键,这正是之前疑问的症结  
  60.                 //首先,普通对象的定义是:通过 "{}" 或者 "new Object" 创建的  
  61.                 //回到之前的疑问,目标对象tobeCloned的属性o对象的obj不是普通对象,也不是数组,所以程序不会走到下面的分支  
  62.                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {  
  63.                     if ( copyIsArray ) {  
  64.                         //如果是数组  
  65.                         copyIsArray = false;  
  66.                         clone = src && jQuery.isArray(src) ? src : [];  
  67.   
  68.                     } else {  
  69.                         clone = src && jQuery.isPlainObject(src) ? src : {};  
  70.                     }  
  71.   
  72.                     // 递归地拷贝  
  73.                     target[ name ] = jQuery.extend( deep, clone, copy );  
  74.   
  75.                 } else if ( copy !== undefined ) {  
  76.                 //会走到这个分支,这个分支的处理很暴力,就是把源对象的属性,直接赋给源对象。  
  77.                 //对于上文中tobeCloned对象的属性o,没有进一步递归地拷贝,而是直接把引用赋给源对象  
  78.                 //所以改变tobeCloned的o属性时,目标对象的o属性也被改变了。  
  79.                     target[ name ] = copy;  
  80.                 }  
  81.             }  
  82.         }  
  83.     }  
  84.   
  85.     // Return the modified object  
  86.     return target;  
  87. };  


  88. 作者:姚大帅
    链接:https://zhuanlan.zhihu.com/p/24570271
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:姚大帅
链接:https://zhuanlan.zhihu.com/p/24570271
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原创粉丝点击