目錄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; } } } }