目录javascript
经过285行的源码 jQuery.extend = jQuery.fn.extend = function() { ,extend方法要么是直接挂在到jQuery的静态方法,要么是挂载到fn上其实就是原型上(参考283行的赋值操做)的实例方法。extend方法能够传一个对象,相似于插件的方式,也能够传多个对象进行拷贝。java
<script src="js/jquery-2.0.3.js"></script> <script> $.extend({ aaa:function(){ alert("1"); }, bbb:function(){ alert("2"); } }) $.fn.extend({ aaa:function(){ alert("3"); }, bbb:function(){ alert("4"); } }) $.aaa();//弹出1,静态方法能够直接调用 $().aaa();//弹出3,绑定到fn上的方法,以对象的形式调用 //多个对象参数,后面的对象会扩展到第一个对象上 var a={}; $.extend(a,{color:'#f40'}); console.log(a);//color所在的对象就被扩展到a对象上 </script>
接下来关注extend的拷贝分深拷贝和浅拷贝。jquery
<script src="js/jquery-2.0.3.js"></script> <script> var a={}; var b={name:"hello"}; var c={name:"hello-1"}; var d={name:{age:20}}; var e={name:{age:50}}; //浅拷贝对象b $.extend(a,b); a.name="hi"; alert(b.name);//弹出hello //浅拷贝对象d $.extend(a,d); a.name.age=30; alert(d.name.age);//弹出30 //深拷贝对象c $.extend(true,a,c); a.name="hi"; alert(c.name);//弹出hello-1 //深拷贝对象e $.extend(true,a,e); a.name.age=40; alert(e.name.age);//弹出50 </script>
分为5个部分:json
定义了一些变量数组
if(){} 是否是深拷贝this
if(){} 参数正确不spa
if(){} 看是否是插件的状况,插件的话传入一个含有方法的json对象插件
for 传入多个对象的状况code
if防止循环应用,if深拷贝,else if浅拷贝。对象
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
这里要说明一下target。它就是 $.extend(a,d); 拷贝的目标对象a。这里的arguments是javascript的内置对象,是一个类数组,索引为0的值固然是参数a。
// 处理深拷贝的情形 if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // 若是传入的第一个参数为true,那么deep就置为true了。target目标对象就调整为第二个。 //跳过布尔值和target i = 2; }
这里处理的是传入了true的状况,好比 $.extend(true,a,c); 。
// 若是传进来的并不是object同时也不是function,那么target置为空对象。 if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; }
// 若是传进来一个参数,那么target目标对象就为jquery本身。 if ( length === i ) { target = this; --i; }
基本思路是经过arguments进行取值,获取到每一个非目标对象的参数。非target对象经过in循环,获取到属性名。
整体特征是浅拷贝只能拷贝一层,深拷贝能够连嵌套子对象也能拷贝进去。
浅拷贝的状况下,那么走的是else分支,对相应的值进行覆盖 target[ name ] = copy; 。能够看到若是原来有target有相同的属性,那么就覆盖,若是没有,那么就添加上。
<script src="js/jquery-2.0.3.js"></script> <script> var a={name:{age:20}}; var b={name:{age:50}}; //浅拷贝对象b $.extend(false,a,b); console.log(a);//{name:{age:20}} console.log(b);//{name:{age:50}} </script>
它遇到对象嵌套,copy这里是{age:50},经过简单的赋值是修改不了的。
<script> var a={name:{age:20}}; var b={name:{age:50}}; a[name]=b[name]; console.log(a);//{name:{age:20}},没有变化哦。 </script>
深拷贝的状况下。copy是数组,src也为数组赋值给clone不然为空数组。copy是对象,src是对象赋值给clone不然为空对象。
<script src="js/jquery-2.0.3.js"></script> <script> var a={name:{age:20}}; var b={name:{age:50}}; //浅拷贝对象b $.extend(true,a,b); console.log(a);//{name:{age:50}} console.log(b);//{name:{age:50}} </script>
深拷贝的copy等于{age:50},src等于{age:20}。那么经过克隆的方式就能够把copy给到src。这实际上是一个递归调用,因此深拷贝会拷贝到底。
for ( ; i < length; i++ ) { // 处理非空或者没有定义的状况 if ( (options = arguments[ i ]) != null ) { // 扩展基础对象,in语法把属性值取出来 for ( name in options ) { src = target[ name ]; copy = options[ name ]; // 防止无限循环,相似$.extend(a,{name:a})。那么若是拷贝的某一个值就等于target那么就终止代码在继续循环 if ( target === copy ) { continue; } // 深拷贝和copy存在,以及copy要么是对象、要么是数组 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 ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } }