深入学习理解jQuery中的extend方法以及JavaScript中对象的复制
来源:互联网 发布:java微信网页授权demo 编辑:程序博客网 时间:2024/05/01 09:19
深入学习理解jQuery中的extend方法以及JavaScript中对象的复制
本文参见的jQuery版本号是:jquery-1.11.1.js
1. jQuery extend方法介绍
查看jQuery的API Document可以发现,extend方法被挂载在了jQuery和jQuery.fn两个不同对象上,但查看jQuery内部代码实现两者确是相同的,只是功能却不太一样;再查看官方的注释:
jQuery.extend(): Merge the contents of two or moreobjects together into the first object.
----把两个或者更多的对象合并到第一个对象当中
jQuery.fn.extend():Merge the contents of an object ontothe jQuery prototype to provide new jQuery instance methods.
----把对象挂载到jQuery的prototype对象上,用以扩展一个新的jQuery实例方法
简单理解两者区别:
jQuery.extend(object):用于将一个或多个对象的内容合并到目标对象。
该函数可以将一个或多个对象的成员属性和方法复制到指定的对象上。
该函数属于全局jQuery对象。
jQuery.fn.extend(object): 函数用于为jQuery扩展一个或多个实例属性和方法(主要用于扩展方法)。
jQuery.fn是jQuery的原型对象,其extend()方法用于为jQuery的原型添加新的属性和方法。这些方法可以在jQuery实例对象上调用。
该函数属于jQuery的原型对象(jQuery.fn)。
2. 关于使用上的区别
静态函数jQuery.extend()有以下两种用法:
用法一:jQuery 1.0 新增该用法。
jQuery.extend(target [, object1 ] [, objectN... ] )
用法二:jQuery 1.1.4 新增该用法。
jQuery.extend([ deep ], target , object1 [, objectN... ] )
用法二是用法一的变体,参数deep用于指示是否深度递归合并。
注意事项:
1、该函数复制的对象属性包括方法在内。此外,还会复制对象继承自原型中的属性(JS内置的对象除外)。
2、参数deep的默认值为false,可以明确指定该参数为true值,但不能明确指定为false值。简而言之,第一个参数不能为false值。
3、如果参数为null或undefined,则该参数将被忽略。
4、如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新 的函数。
5、如果多个对象具有相同的属性,则后者会覆盖前者的属性值。
6、改函数的返回值为参数target代表的对象。
插播深度复制的一些知识:
jQuery中深度复制,是将除null,undefined,window对象,dom对象,通过继承创建的对象外的其它对象克隆后保存到target中;之所以排除部分对象,一是考虑性能,二是考虑复杂度(如dom、window对象,如果克隆复制,消耗过大,而通过继承实现的对象,复杂程度不可预知,因此也不进行深度复制);
深度与非深度复制区别是,深度复制的对象中如果有复杂属性值(如数组、函数、json对象等),那将会递归属性值的复制,合并后的对象修改属性值不影响原对象
静态函数jQuery.fn.extend( object )的用法:jQuery 1.0 新增该静态函数。
jQuery.fn.extend()函数的返回值是Object类型,返回jQuery的原型对象(即jQuery.fn)。
$.extend深度复制的使用示例:
extend(boolean,dest,src1,src2,src3...)
第一个参数boolean代表是否进行深度拷贝,其余参数和前面介绍的一致,什么叫深层拷贝,我们看一个例子:
var result=$.extend( true, {}, { name: "John", location: {city: "Boston",county:"USA"} }, { last: "Resig", location: {state: "MA",county:"China"} } );///<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333339691162px; line-height: 21.6666679382324px; white-space: pre-wrap; background-color: rgb(255, 255, 255);">我们可以看到参数src1中嵌套有子对象location:{city:"Boston"}, src2中也嵌套了同名的子对象location:{state:"MA"},然后我们设置了第一个深度拷贝参数的值为true,那么合并后的结果就是: </span>
<span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13.3333339691162px; line-height: 21.6666679382324px; background-color: rgb(255, 255, 255);"></span><pre name="code" class="javascript">result={name:"John",last:"Resig", location:{city:"Boston",state:"MA",county:"China"}}// 也就是说它会将src中的嵌套子对象也进行合并,而如果第一个参数boolean为false,我们看看合并的结果是什么,如下:
var result=$.extend( false, {}, { name: "John", location:{city: "Boston",county:"USA"} }, { last: "Resig", location: {state: "MA",county:"China"} } );
那么合并后的结果就是:
result={name:"John",last:"Resig",location:{state:"MA",county:"China"}}
3.jQuery源码实现
先来看看jQuery中源代码的实现:
jQuery.extend = jQuery.fn.extend = function() {var src, copyIsArray, copy, name, options, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif ( typeof target === "boolean" ) {deep = target;// skip the boolean and the targettarget = arguments[ i ] || {};i++;}// Handle case when target is a string or something (possible in deep copy)if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}// extend jQuery itself if only one argument is passedif ( i === length ) {target = this;i--;}for ( ; i < length; i++ ) {// Only deal with non-null/undefined valuesif ( (options = arguments[ i ]) != null ) {// Extend the base objectfor ( name in options ) {src = target[ name ];copy = options[ name ];// Prevent never-ending loopif ( target === copy ) {continue;}// Recurse if we're merging plain objects or arraysif ( 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 : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy );// Don't bring in undefined values} else if ( copy !== undefined ) {target[ name ] = copy;}}}}// Return the modified objectreturn target;};
关于上面代码的注释版本:
jQuery.extend = jQuery.fn.extend = function() {// i 此处初始值为 1 ,主要是为了便于区分深度复制时,确保target对象的正确性var src, copyIsArray, copy, name, options, clone,target = arguments[0] || {},i = 1,length = arguments.length,deep = false;// Handle a deep copy situationif ( typeof target === "boolean" ) { // 第一个参数如果是Boolean类型则进行赋值深度的选择deep = target;// skip the boolean and the target// 如果没有传入target对象并且第一个参数是boolean类型是,新创建一个对象,用于赋值target = arguments[ i ] || {}; i++;}// Handle case when target is a string or something (possible in deep copy)if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}// extend jQuery itself if only one argument is passedif ( i === length ) { // 英文注释已经表明了,如果只有一个参数,target对象为jQuery自身target = this;i--;}// 对从i开始的多个参数进行遍历for ( ; i < length; i++ ) {// Only deal with non-null/undefined values// 只处理有定义的值if ( (options = arguments[ i ]) != null ) {// Extend the base object// 展开扩展对象for ( name in options ) {src = target[ name ];copy = options[ name ];// Prevent never-ending loop// 防止循环引用if ( target === copy ) {continue;}// Recurse if we're merging plain objects or arrays// 递归处理深拷贝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 : {};}// Never move original objects, clone themtarget[ name ] = jQuery.extend( deep, clone, copy );// Don't bring in undefined values// 不处理未定义值} else if ( copy !== undefined ) { //给target增加属性或方法target[ name ] = copy;}}}}// Return the modified objectreturn target;};
代码的大部分都是用来实现jQuery.extend()中有多个参数时的对象合并,深度拷贝问题,如果去掉这些功能,让extend只有扩展静态和实例方法的功能,那么代码如下:
jQuery.extend = jQuery.fn.extend = function(object){ //object是传递过来扩展到this上的对象 var target = this; for (var name in object){ //name为对象属性 //copy为属性值 copy = obj[name]; //防止循环调用 if(target === copy) continue; //防止附加未定义值 if(typeof copy === 'undefined') continue; //赋值 target[name]=copy; } return target;}
4.关于复制深浅的学习与讨论:
先利用jQuery中的extend()来窥探一下深浅复制的区别,先来一个整体感知:
<!DOCTYPE html><html><head><script src="jquery-1.11.1.js"></script><script>varobj1 = { a : 'a', b : 'b' },obj2 = {},obj3 = { x : { xxx : 'oldValue', yyy : 'yyy' }, y : 'y' }; $.extend(true, obj1, obj3); // 第一个参数为true表示执行深度复制$.extend(obj2, obj3); // deep的默认值为false,表示前复制console.log(obj1.x.xxx); // 输出"oldValue" obj3.x.xxx = 'newVlaue'; console.log(obj3.x.xxx); // 输出"newValue" console.log(obj1.x.xxx); // 输出"oldValue" 因为是深度复制,所以obj1中的属性值的改变不会再obj2中得到体现console.log(obj2.x.xxx); // 输出"newValue" 因为是浅赋值,仅仅是简单的给对象多添加了一个引用而已</script></head><body></body></html>
在感知有了一个整体的感知后,我们开始来探讨关于深浅复制的基本实现问题:
(1):浅复制的实现:(基于源码进行精简,更过具体实现可以去参考一下《JavaScript高级程序设计》,我记得里面有很多讨论的地方!)
$ = { extend : function(target, options) { for (name in options) { target[name] = options[name]; } return target; } };
(2):深赋值的实现:(还是基于jQuery源码进行精简的,并没有考虑DOM、Window对象这些的过滤,也没有考虑IE的兼容,听见IE不再更新的时候,心情那叫一个酸爽~~~)
$ = { extend : function(deep, target, options) { for (name in options) { copy = options[name]; // 赋值过程中对属性的具体类型进行区别处理,这里只是简单的处理了一下 if (deep && copy instanceof Array) { target[name] = $.extend(deep, [], copy); } else if (deep && copy instanceof Object) { target[name] = $.extend(deep, {}, copy); } else { target[name] = options[name]; } } return target; } };
- 深入学习理解jQuery中的extend方法以及JavaScript中对象的复制
- 深入理解jquery中extend的实现
- javascript中的深复制方法一:jQuery中的extend方法
- jQuery源码分析以及从jQuery对象创建的角度理解extend方法的原理
- Jquery的extend方法$.extend()学习
- 原生js实现复制对象、扩展对象 类似jquery中的extend()方法
- 原生js实现复制对象、扩展对象 类似jquery中的extend()方法
- jQuery中jQuery.extend()和jQuery.fn.extend()的理解
- jQuery中的extend方法
- jQuery中的extend方法
- 关于jquery中的extend方法的用法
- 深入理解object C中复制对象的用法
- jQuery中的$.extend方法来扩展JSON对象
- Javascript中extend方法的实现
- javascript对象 以及对象属性深入学习
- javascript 对象的深入理解
- jquery的extend和fn.extend (扩展jQuery类或jQuery对象方法)
- Jquery的$.extend方法
- 与罗胖一起追寻内心平静
- 处理MySQL复制环境Slave故障的一个案例
- csdn博客我来了
- 关于socket的readLine和read问题
- 6.x版本centos虚拟机安装和U盘安装
- 深入学习理解jQuery中的extend方法以及JavaScript中对象的复制
- 输入一个int型数据,计算出该int型数据在内存中存储时1的个数。
- Eclipse 安装spring插件
- 一元多项式的表示及相加 【链表的应用】
- Java大文件按行切割
- 如何计算IP地址
- Linux下tcp并发服务器的几种设计的模式套路
- 汇编后缀导致了编译错误(一个极难发现的错误)
- 八皇后问题