jQuery.extend 与 jQuery.fn.extend
extend方法为jQuery对象的核心之一,语法如下:
jQuery.extend([deep], target, object1, [objectN]),返回值Object。
概述:用一个或多个其它对象来扩展一个对象,返回被扩展的对象。
如果不指定target,则给Jquery命名空间本身进行扩展。这有助于插件作者为Jquery增加新方法。
如果第一个参数设置为true,则Jquery返回一个深层次的副本,递归地复制找到的任何对象。否则的话,副本会与原对象共享结构。未定义的属性将不会被复制,然而从对象的原型继承的属性将会被复制。
参数:target,[object1],[objectN] Object,Object,Object
target:一个对象,如果附加的对象被传递给这个方法将那么它将接收新的属性,如果它是唯一的参数将扩展jQuery的命名空间。
object1:待合并到第一个对象的对象。
objectN:待合并到第一个对象的对象。
[deep],target,object1,[objectN] Object,Object,Object,Object
deep:如果设为true,则递归合并。
target:待修改对象。
object1:待合并到第一个对象的对象。
objectN:待合并到第一个对象的对象。
示例:
var ts = function () {this.age = 23;} console.log($.extend([1,2,3],[4,5,6,7])); // 结果:[4,5,6,7] console.log($.extend(false, new ts(), { age: 12, name: "lisi" })); //结果: Object {age: 12, name: "lisi"} console.log($.extend({ age: 43, name: "张三" }, { sex: "男", height: 180 }, { job: "警察" })); //结果:Object {age: 43, name: "张三", sex: "男", height: 180, job: "警察"} console.log($.extend(true, { age: 23, child: { age: 1, sex: "男" } }, { name: '张三', child: { name: "李四" } })); //结果:Object {age: 23, child: {age:1,name:'李四',sex:'男'}, name: "张三"} console.log($.extend(false, { age: 23, child: { age: 1, sex: "男" } }, { name: '张三', child: { name: "李四" } })); //结果:Object {age: 23, child: {name:"李四"}, name: "张三"} console.log($.extend(true)) //结果: Object {}
在看源码之前我们先了解下深拷贝和浅拷贝:
浅拷贝 :仅仅复制对象的引用,而不是对象本身;
深拷贝:把复制的对象所引用的全部对象都复制一遍。
浅拷贝例子:
/* ================ 浅拷贝 ================ */ function simpleClone(initalObj) { var obj = {}; for ( var i in initalObj) { obj[i] = initalObj[i]; } return obj; }
深拷贝例子:
/* ================ 深拷贝 ================ */ function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { if (typeof initalObj[i] === 'object') { obj[i] = (initalObj[i].constructor === Array) ? [] : {}; arguments.callee(initalObj[i], obj[i]); } else { obj[i] = initalObj[i]; } } return obj; }
有了深拷贝和浅拷贝的介绍,我们再来看 Jquery.extend的源码分析:
jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, //20170614 huanhua 需要被合并的对象的临时变量 clone, target = arguments[0] || {}, //huanhua 20170614 第一个参数赋值给 target ,需要合并到的对象 target i = 1, //huanhua 20170614 被合并的对象,在参数中的起始位置,默认是第二个参数,索引下标就是1 length = arguments.length, deep = false; //huanhua 20170614 深浅拷贝,默认是浅拷贝 // Handle a deep copy situation // 20170614 huanhua 处理类似 jquery.extend(true,{age:23,child:{age:1,sex:"男"}},{name:'张三',child:{name:"李四"}})这种扩展 if ( typeof target === "boolean" ) { deep = target; //huanhua 20170614 设置是深拷贝还是浅拷贝 target = arguments[1] || {}; //huanhua 20170614 此时需要合并到的对象是第二个参数 // skip the boolean and the target i = 2; //20170614 huanhua 在进行深浅拷贝时,需要被合并的对象的起始位置是第3个参数,索引下标就是2开始 } // Handle case when target is a string or something (possible in deep copy) // 20170614 huanhua 处理类似 $.extend("hshshdhd", [4, 5, 6, 7]) 结果:Object {0: 4, 1: 5, 2: 6, 3: 7}这种的扩展 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; //20170614 huanhua 被扩展的对象,扩展到一个对象上 } // extend jQuery itself if only one argument is passed // 20170614 huanhau 处理类似 $.extend({name:"张哈"}) 这种,只有一个参数,并且还不是 $.extend(true)这种的参数格式 //此时参数的长度是1,i也是1 if ( length === i ) { target = this;//20170614 huanhua 需要扩展到的对象就是jquery自己 --i; //20170614 huanhua 需要被合并的对象起始位置就是第一个参数,所以索引下标就是从 (--i)0开始 } //20170614 huanhua 从需要被合并的对象的起始位置开始循环处理合并 for ( ; i < length; i++ ) { // Only deal with non-null/undefined values //20170614 huanhua 把需要被合并的对象赋值给 options ,并且只处理 非 null,非 undefined 的对象 if ( (options = arguments[ i ]) != null ) { // Extend the base object //20170614 huanhua 开始合并对象 for ( name in options ) { //20170614 huanhua 在需要被扩展到的对象中寻找需要扩展的对象属性,并赋值给 src src = target[ name ]; //20170614 huanhua 把需要被扩展的对象属性赋值给copy copy = options[ name ]; // Prevent never-ending loop //20170614 huanhua var o={w:2} $.extend(o,{hao:o}),结果 Object {w:2} 处理这种扩展,在递归深拷贝的时候以防死循环 //20170614 huanhua 譬如: // var o = { n: o }; // var xh = 0; // var f = function (o) { // for (var m in o) { // console.log((xh++)); // console.log(m); // f(m); // } // } // f(o); // 在递归运行的时候,就是一个死循环 if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays //20170614 huanhua 需要深拷贝deep,并且需要拷贝的属性copy是有效的(非null,非undefined), //并且需要拷贝copy的属性是纯粹的对象({a:1}或者new object())或者数组 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { //20170614 huanhua 拷贝的是数组 if ( copyIsArray ) { copyIsArray = false; //20170614 huanhua如果需要扩展到的对象中不存在属性src = target[ name ],或者不是数组格式的, //就重新用生成一个空的数组 [] 来装载扩展的数据,否则就用原来的属性来装载数据 clone = src && jQuery.isArray(src) ? src : []; } else { //20170614 huanhua如果需要扩展到的对象中不存在属性src = target[ name ],或者不是纯粹对象格式的, //就重新用生成一个空的对象 {} 来装载扩展的数据,否则就用原来的属性来装载数据 clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them //20170614 huanhua 递归扩展属性对象中的每一个属性 target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values //20170614 huanhua 其它的合并就浅拷贝,直接赋值或者添加属性 } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object 20170614 huanhua 返回合并后的对象 return target; };
javascript的继承有三种方式
1:原型继承。
2:类式继承。
3:拷贝继承。
Juqery采用的就是拷贝继承。
这只是个人的理解,有不对之处,望各位大神们指正。