JQuery _ $.extend(true,{},object...) 的不完全深复制 与 源代码详解
来源:互联网 发布:淘宝收藏宝贝没反应 编辑:程序博客网 时间:2024/06/10 22:11
大家如果用过JQuery 的 extend 函数, 一定对 extend 函数 有一定了解。
但是 extend 的深复制也不是 完美, 下面通过 一个例子 与 JQuery 源码 进行分析:
使用extend时,如果第一个参数传入的是true,则表示需要进行“深拷贝”。但是这是个不完全的深复制,见下面例子:
function Obj(){ this.a = 1;}var obj = new Obj();var tobeCloned = {o:obj};var result = $.extend(true,{},tobeCloned);tobeCloned.o.a = 2;console.log(result.o.a);//输出是什么呢?
按照一般的深复制理解,结果输出 应该为 1,但是实际结果却为 2
让我们去看看JQuery 源代码就明白了:
请看jquery.extend函数的注释版源码(版本为1.7)
JQuery 源代码:
jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; /* 变量 options:指向某个源对象。 变量 name:表示某个源对象的某个属性名。 变量 src:表示目标对象的某个属性的原始值。 变量 copy:表示某个源对象的某个属性的值。 变量 copyIsArray:指示变量 copy 是否是数组。 变量 clone:表示深度复制时原始值的修正值。 变量 target:指向目标对象,申明时先临时用第一个参数值。 变量 i:表示源对象的起始下标,申明时先临时用第二个参数值。 变量 length:表示参数的个数,用于修正变量 target。 变量 deep:指示是否执行深度复制,默认为 false。 ps:源对象指的是把自己的值付给别人的对象;目标对象指的是被源对象赋值的对象 */ // 如果第一个参数传入的是布尔值 if ( typeof target === "boolean" ) { deep = target;//设置deep变量,确定是深拷贝还是浅拷贝 target = arguments[1] || {};//将目标对象设为第二个参数值。 i = 2;//源对象的起始下标设为2(即从第三个参数开始算源对象) } // Handle case when target is a string or something (possible in deep copy) //嗯,原英文解释的很清楚 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 如果没有目标对象,那么目标对象就是jquery对象 if ( length === i ) { target = this; --i; } 拷贝的核心部分代码 for ( ; i < length; i++ ) {//遍历源对象 // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) {//options就是源对象 // Extend the base object for ( name in options ) {//遍历源对象的属性名 src = target[ name ];//获取目标对象上,属性名对应的属性 copy = options[ name ];//获取源对象上,属性名对应的属性 // 如果复制值copy 与目标对象target相等, //为了避免深度遍历时死循环,因此不会覆盖目标对象的同名属性。 if ( target === copy ) { continue; } //递归地将源对象上的属性值合并到目标对象上 //如果是深拷贝,且待拷贝的对象存在,且是普通对象或是数组 //这一个判断条件非常关键,这正是之前疑问的症结 //首先,普通对象的定义是:通过 "{}" 或者 "new Object" 创建的 //回到之前的疑问,目标对象tobeCloned的属性o对象的obj不是普通对象,也不是数组,所以程序不会走到下面的分支 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 ); } else if ( copy !== undefined ) { //会走到这个分支,这个分支的处理很暴力,就是把源对象的属性,直接赋给源对象。 //对于上文中tobeCloned对象的属性o,没有进一步递归地拷贝,而是直接把引用赋给源对象 //所以改变tobeCloned的o属性时,目标对象的o属性也被改变了。 target[ name ] = copy; } } } } // Return the modified object return target;};
通过以上代码,大家应该对这个问题有了明确的答案。
作者:姚大帅
链接:https://zhuanlan.zhihu.com/p/24570271
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
0 0
- JQuery _ $.extend(true,{},object...) 的不完全深复制 与 源代码详解
- jQuery.extend(object) 与 jQuery.fn.extend(object)的区别
- jQuery.fn.extend(object);和jQuery.extend(object); 的理解
- jquery的extend详解
- $.extend(true,o,d)与$.extend(o,d) 的区别
- jQuery.extend $.extend详解
- JQuery的extend扩展详解
- jquery的extend方法详解
- JQuery的extend方法详解
- JQuery的extend方法详解
- jQuery插件( jquery.extend 与 jquery.fn.extend的区别)
- 学习jquery源代码---$.extend
- prototype详解Object.extend
- jquery.fn.extend与jquery.extend的区别和使用
- jquery.extend 与 jquery.fn.extend的区别和使用
- jquery.fn.extend与jquery.extend的区别和使用
- jquery.fn.extend与jquery.extend的用法
- jquery.extend() 与 jquery.fn.extend() 的区别
- [bzoj4573][UOJ#195][ZJOI2016]大森林
- 由浅入深分布式(5)dubbo提供者用内网地址注册provider以及 spring boot admin client用主机名注册spring boot admin server
- 架构设计:负载均衡层设计方案(3)——Nginx进阶
- php数字证书的签名和验签
- 在socket系统调用中,如何完成三次握手和四次挥手
- JQuery _ $.extend(true,{},object...) 的不完全深复制 与 源代码详解
- 基于HTML5+bootstrap实现类似贪吃蛇游戏
- angularjs中的指令
- 数据库水平切分的实现原理解析——分库,分表,主从,集群,负载均衡器(转)
- Java自动生成Mvp框架目录结构
- Codeforces 768B Code For 1
- Xcode无开发者账号真机测试
- Android开发--fragment中Button点击切换Activity
- IntelliJ IDEA 创建并部署单纯的web工程(不用Maven和Gradle管理)