1.變量的含義:
var target
,options /* 指向源對(duì)象 */
,name, /* 鍵名 */
,i = 1 /* 指向的源對(duì)象在arguments中的索引 */
,length = arguments.length /* 參數(shù)的個(gè)數(shù) */
,deep = false /* 標(biāo)志是否深拷貝,沒有boolean值的時(shí)候默認(rèn)為flase谨履,淺復(fù)制 */
,src /* 存儲(chǔ)target對(duì)象的當(dāng)前屬性 */
,copy /* 存儲(chǔ)源對(duì)象當(dāng)前屬性的值 */
,target = arguments[0] || {} /* 過濾掉undefined 和 null */
,clone; /* 深復(fù)制時(shí)候存放target[name]值 */
,copyIsArray; /* 存放一個(gè)標(biāo)志妓笙,表示源對(duì)象當(dāng)前屬性值是否是數(shù)組 */
2.if代碼塊1:extend函數(shù)提供用戶指定是否深拷貝的功能通過在第一個(gè)參數(shù)傳遞boolean值喳坠,檢測函數(shù)第一個(gè)值是否是boolean值停做。
2.1. 第一個(gè)參數(shù)是boolean時(shí)候執(zhí)行灸异。
2.2. 第一個(gè)參數(shù)是boolean類型即是target的指向錯(cuò)了,i指向也錯(cuò)了绍昂,必須進(jìn)行修改,并且重置deep標(biāo)志狂秦。
/* 1.第一個(gè)參數(shù)是boolean時(shí)候執(zhí)行灌侣,
2.第一個(gè)參數(shù)是boolean類型即是target的指向錯(cuò)了,i指向也錯(cuò)了,必須進(jìn)行修改裂问,并且重置deep標(biāo)志
*/
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {}; /* 過濾第2個(gè)參數(shù)值為undefined,null */
i = 2;
}
3.if代碼塊2:因?yàn)閖s中對(duì)那些不是對(duì)象不是函數(shù)的值設(shè)置屬性方法是無效的,這里過濾這些值侧啼,保證target指向一個(gè)可以設(shè)置屬性的對(duì)象。
3.1. if語句:滿足target不是對(duì)象也不是函數(shù)時(shí)執(zhí)行堪簿。
3.2. 滿足條件的target值有可能是以字面量方式創(chuàng)建的boolean,number,string痊乾。
3.3. 不會(huì)出現(xiàn)target值為undefined和null,前面初始化時(shí)候已經(jīng)過濾椭更。
if ( typeof target !== "object"
&& !jQuery.isFunction(target) ) {
target = {};
}
4.if代碼塊3:extend()函數(shù)實(shí)現(xiàn)了當(dāng)傳入的參數(shù)有效對(duì)象個(gè)數(shù)不足夠賦值給target和源對(duì)象時(shí)哪审,默認(rèn)將target指向自身。
4.1. arguments長度等于i的值得時(shí)候虑瀑,表示target = arguments[arguments.length-1],
這時(shí)候的源對(duì)象是arguments[arguments.length] = undefined湿滓,顯然這是沒意義的滴须。
4.2. jQuery在出現(xiàn)這種情況時(shí),將target對(duì)象設(shè)置為自身叽奥,然后修改i指向target原先的指向扔水。
4.3. 我們可以通過這個(gè)方法對(duì)jQuery進(jìn)行擴(kuò)展。
if ( length === i ) {
target = this;
--i;
}
5.for代碼塊朝氓,實(shí)現(xiàn)target對(duì)象擴(kuò)展魔市,從第一個(gè)源對(duì)象開始遍歷arguments。
for ( ; i < length; i++ ) {
/* 以上我們已經(jīng)將arguments中的項(xiàng)過濾到target指向赵哲,以下if在源對(duì)象值為undefiend和null時(shí)進(jìn)行過濾*/
if ( (options = arguments[ i ]) != null ) {
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
/* 為了避免在遞歸深拷貝過程中待德,出現(xiàn)了無限循環(huán):(看后面代碼片1,2)
1.向extend()方法傳入的源對(duì)象擁有屬性值為目標(biāo)對(duì)象枫夺,并且目標(biāo)對(duì)象中有屬性引用了目標(biāo)對(duì)象本身将宪,
2.源對(duì)象的屬性引用了源對(duì)象自身*/
if ( target === copy ) {
continue;
}
/* 判斷是否滿足深拷貝的條件:
1.deep標(biāo)志為true,
2.源對(duì)象當(dāng)前屬性(name)的值存在,
3.源對(duì)象當(dāng)前屬性值是數(shù)組,{}或者是由Object創(chuàng)建的對(duì)象*/
if ( deep
&& copy
&& ( jQuery.isPlainObject(copy)
|| (copyIsArray = jQuery.isArray(copy)) ) ) {
/* copyIsArray 是標(biāo)示源對(duì)象當(dāng)前屬性值是否是數(shù)組,通過這個(gè)標(biāo)志分別對(duì)源對(duì)象當(dāng)前屬性
值為對(duì)象和源對(duì)象當(dāng)前屬性值為數(shù)組的情況分開處理*/
if ( copyIsArray ) {
/* 如果不設(shè)置為false,下一次既使?jié)M足深拷貝的條件進(jìn)入后橡庞,如果源對(duì)象當(dāng)前屬性值為對(duì)象涧偷,會(huì)按照數(shù)組進(jìn)行處理*/
copyIsArray = false;
/* clone存放了target[name]的值,值的如果不存在或者類型不是數(shù)組時(shí)毙死,將其賦值空數(shù)組燎潮,否則值不改變 */
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
/* 遞歸調(diào)用extend進(jìn)行深拷貝*/
target[ name ] = jQuery.extend( deep, clone, copy );
/* 過濾源對(duì)象屬性值為undefined的屬性,沒有過濾屬性值為null的屬性,看以下代碼片3*/
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
/* 返回修改后的對(duì)象*/
return target;
};
6.代碼片1
/* 1.target對(duì)象屬性值引用自身扼倘,并且original對(duì)象的屬性引用target,注釋if(target == copy)中的continue后無限循環(huán)最后
報(bào)錯(cuò)*/
/* 2.錯(cuò)誤信息:Uncaught RangeError: Maximum call stack size exceeded(超過最大調(diào)用堆棧內(nèi)存)*/
var target = {};
target.proper = target;
var original = {};
original.proper = target;
$.extend(true,target,original);
7.代碼片2
/*bug:
2.original對(duì)象存在屬性引用其自身,報(bào)錯(cuò)信息和上面一致 */
var target = {};
target.proper = '屬性';
var original = {};
original.proper = original;
console.log($.extend(true,target,original));
8.代碼片3
/* 過濾掉屬性值為undefiend的屬性确封,沒過濾屬性值為null的屬性,可以測試以下代碼:可以修改copy!= undefined來實(shí)現(xiàn)過濾null*/
var target = {}
var original = {
name: null
}
console.log($.extend(target,original));