jq中extend函式中的deep引數
昨天在研究繼續研究JS外掛的時候注意到了extend這個函式,然後就用幾個示例去加深對它的印象,不過在過程中對於deep這個引數產生了疑惑。當jq1.1.4版本後extend這個函式增加了一個引數deep,用來進行選擇是否深拷貝,深淺拷貝這裡我就不說了,這裡直接用例子來看一下
給出3個例子,大家應該就明白了:
1.我們可以發現當我們去改變a中的age值的時候,b中改變
var a = {tom: { age: 15 }}; var b = { tom: { age: 14 } } extend(a, b); a.tom.age = 25; console.log(a.tom.age); //25 console.log(b.tom.age);//25
2.我們可以發現當我們去改變a中的age值的時候,b中沒有改變
var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(true,a, b);
a.tom.age = 25;
console.log(a.tom.age); //25
console.log(b.tom.age);//14
3.我們可以發現當我們去改變a中的age值的時候,b中沒有改變
var a = {tom: { age: 15 }}; var b = { tom: { age: 14 } } extend(false,a, b); a.tom.age = 25; console.log(a.tom.age); //25 console.log(b.tom.age);//14
我們可以發現3個例子的區別就是第一個引數deep是否存在和為true和false,而且第一個例子是淺拷貝,第二個和第三個都是深拷貝
這裡可以有2個結論:
1.這個函式預設就是淺拷貝
2.傳true和false都是深拷貝
一開始對於第2個結論很不理解,講道理true為深拷貝,那麼false肯定為淺拷貝呀,為什麼都一樣呢?在網上查了很多資料,發現還是不明白,後來去官網查了一下知道(證明以後我們查東西還是去官網比較靠譜,網上很多部落格都是斷章取義),第一個引數不能為false。https://api.jquery.com/jquery.extend/
(可以去看中文的文件,也可以用chrome瀏覽器翻譯)
Warning: Passingfalse
for the first argument is not supported.
原來不能傳false,之所以這樣是我們一直都是慣性思維,理解true為深,那麼false肯定為淺咯~ -。-(慣性思維害死人,我還一直糾結為什麼會這樣)
其實到這裡我們都是知其然,不知其所以然,在糾結這個問題的過程中,我查了原始碼,終於知道其所以然了。
target = arguments [ 0 ] | | { }
//就是這一句話~(大家可以定位到這句話),它是把這個函式的第一個引數傳遞給target,最重要的是這裡用了一個 | | 或,如果當我第一個是假的話就直接賦值一個空物件給target,這樣就可以理解,為什麼我們可以傳true不能傳false了,當我們傳true的時候為真,它就直接把true給它了,當我傳false的時候為假,它就會把一個空物件給target。
因為上面這個條件,我們就可以解釋為什麼當進行後面那個判斷時,我傳false會進不去的原因了,就是因為typeof (target)為object!!!!!
if ( typeof (target) === "boolean" ) {//如果第一個引數是boolean型別,則將該引數賦給deep,即是否深拷貝
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
然後再看一個例子:
var empty={};
var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
extend(empty,a,b);
empty.tom.age = 25;
console.log(empty.tom.age);//25
console.log(a.tom.age); //15
console.log(b.tom.age);//25
我們可以發現,當我們去淺拷貝的時候,它只是會影響到最後一個物件的引數,這個也可以理解,因為後面的引數會覆蓋前面的,所以淺拷貝的時候,最後被合併的物件(empty)引用的是最後一個引數物件( b )的屬性。
所以當我們對外掛引數進行覆蓋的時候最好用這種方式:
第一個引數為true,第二個引數為空物件,就是為了不讓其他物件的值被覆蓋掉。
var empty={};
var a = {tom: { age: 15 }};
var b = { tom: { age: 14 } }
empty=extend(true,{},a,b);
empty.tom.age = 25;
console.log(empty.tom.age);//25
console.log(a.tom.age); //15
console.log(b.tom.age);//14
最後附上別人對這個函式的原始碼解析:
jQuery.extend = jQuery.fn.extend = function() {
/*
傳入的物件分為擴充套件物件和被擴充套件物件
*/
var options, name, src, copy, copyIsArray, clone, //
target = arguments[0] || {}, //被擴充套件的物件
i = 1, //設定擴充套件物件的起始值,預設從第二項開始
length = arguments.length, //傳遞引數的個數,以便下面迴圈擴充套件物件使用
deep = false; //預設淺複製
/*
處理深層拷貝或淺拷貝情況
extend(Boolean,src1,src2..srcN);
*/
if ( typeof target === "boolean" ) {
deep = target; //將deep設為target,此時target為傳進來的Boolean值,true or false;
target = arguments[ i ] || {}; //重新設定被擴充套件物件,為引數的第二項
i++; //重設擴充套件物件的起始值,從第三項開始
}
/*
被擴充套件的不是物件或函式,可能是String,Number或其他;
extend("",src1,src2...srcN);
*/
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {}; //重新設定target的值為空物件
}
/*
當只傳入一個物件
extend(src1);
將target設為jQuery物件或者jQuery.prototype,來擴充套件jQuery靜態屬性方法或是例項屬性方法
$.extend(src1); //擴充套件jQuery物件
$.fn.extend(src1) //擴充套件jQuery.prototype
*/
if ( i === length ) {
target = this;
i--; //重設擴充套件物件起始值,從第0個開始
}
/*
被擴充套件物件和擴充套件物件所有情況處理完畢,開始迴圈進行拷貝
對從i開始的多個引數進行遍歷
*/
for ( ; i < length; i++ ) {
if ( (options = arguments[ i ]) != null ) { //只處理有定義擴充套件物件
//擴充套件基本物件
for ( name in options ) { //迴圈每一項擴充套件物件
src = target[ name ];
copy = options[ name ];
// 防止迴圈引用,window === window.window.window
if ( target === copy ) {
continue;
}
/*
物件或陣列做深拷貝
deep:判斷是否要深拷貝
copy:保證copy存在
jQuery.isPlainObject:判斷copy是否是一個純粹的物件,通過{} 或 new Object 建立
jQuery.isArray:判斷是否為陣列
*/
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
//為陣列
if ( copyIsArray ) {
copyIsArray = false; //設為false,以便下次再重新判斷是否為陣列
clone = src && jQuery.isArray(src) ? src : []; //設定clone為一個數組
} else {
clone = src && jQuery.isPlainObject(src) ? src : {}; //設定clone為一個物件
}
//遞迴深度拷貝
target[ name ] = jQuery.extend( deep, clone, copy );
//過濾未定義的值
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
//返回修改後的物件
return target;
};
相關推薦
jq中extend函式中的deep引數
昨天在研究繼續研究JS外掛的時候注意到了extend這個函式,然後就用幾個示例去加深對它的印象,不過在過程中對於deep這個引數產生了疑惑。當jq1.1.4版本後extend這個函式增加了一個引數deep,用來進行選擇是否深拷貝,深淺拷貝這裡我就不說了,這裡直
C++中main函式中引數argc和argv的使用例項
含義解釋 (1).int argc:即為arguments count(引數數) 執行程式傳送給main函式命令列引數的總數,包括可執行程式名。當argc=1時表示只有一個程式名稱,此時儲存在argv
JS中建構函式中有return的分析
目錄 寫在前面 demo幫助理解 寫在前面 簡單的總結來說就一句話:如果return的值是基本資料型別的話,則忽略return,直接返回例項化的物件;如果return的值是引用型別的話,則不再返回例項化的物件,而是直接返回return返回的引用型別的值。 demo幫助理解
java中main函式中的變數定義及其使用
public class exe1 { static int i=10; int k=3; public static void main(String[] args) { k=5; System.out.println("i="+i); System.out.println("k="+k); } } 報
MFC中SetWorldTransform函式中XFORM結構體的使用
使用XFORM來控制DC時,需要先設定繪圖模式SetGraphicsMode為GM_ADVANCED,再用SetWorldTransform。否則SetWorldTransform函式會失敗對映後的座標與對映前的座標關係為x' = x * eM11 + y * eM21 +
[Python筆記]函式中關鍵字引數,收集引數與分配引數的使用例項
Stock類 class Stock: def __init__(self): self.itemList = [] def addItem(self, name, price): # 建立商品 return {'name': name
c和C++main函式中引數的意義和用法
main函式是C++的主函式,除了程式本身外,任何函式都不可以呼叫main函式。main函式中可以新增引數,也可以不寫。main函式預設有兩個引數,main(int argc, char ** argv),其中,argc是用來表面main函式究竟呼叫了幾個引數,因為程式本身的檔名就是一個
JS中的函式引數傳遞到底是按值傳遞還是按引用傳遞
首先我們知道JS中的資料型別大致可以分為簡單資料型別和複雜資料型別; 當我們宣告一個變數並給它賦值時,可以賦給其簡單值和複雜值(以下堆記憶體和棧記憶體的地址表示均隨意取的,只是為了區分,不代表真實的記憶體地址); 針對簡單資料型別: 例1 var simpleData1 = 18 v
main函式中兩個引數的用法總結
1、定義 C語言規定main函式的引數只能有兩個,習慣上這兩個引數寫為argc和argv。因此,main函式的函式頭可寫為: main (argc,argv)C語言還規定argc(第一個形參)必須是整型變數,argv( 第二個形參)必須是指向字串的指標陣列。加上形參說明後,main函式的
getopt----解析main函式中的引數
轉自------ Linux下getopt()函式的簡單使用 "a:b:cd::e",這就是一個選項字串。對應到命令列就是-a ,-b ,-c ,-d, -e 。冒號又是什麼呢? 冒號表示引數,一個冒號就表示這個選項後面必須
不可不知:函式中預設引數的陷阱
現象 def foo(x, y=[]): y.append(x) return y print(foo(1)) print(foo(1, [3, 4])) print(foo(5)) ''' [1] [3, 4, 1] [1, 5] '''  
函式中的引數為object... 和 object[] 的區別
先給出兩個示例函式 方法1: public void testobject(object... params){ ///省略此處程式碼 } 方法2: public void testobject(object[] params){ ///省略此處程式碼 } 區別
Java程式利用main函式中args引數實現引數的傳遞
1.執行Java程式的同時,可以通過輸入引數給main函式中的接收引數陣列args[],供程式內部使用!即當你在Java命令列後面帶上引數,Java虛擬機器就直接把它們存放到了main方法中的引數String數組裡了。 2..args是Java命令列引數,因為引數可以為多個,所以要用陣列來存
Python中函式定義及引數例項
1.函式定義 函式就是完成特定功能的一個語句組,這組語句可以作為一個單位使用,並且給它取一個名字 ,可以通過函式名在程式的不同地方多次執行(這通常叫函式呼叫) 預定義函式(可以直接使用) 自定義函式(自己編寫) 為什麼使用函式? 降低程式設計難度,通常將
Python函式中多型別傳值和冗餘引數及函式的遞迴呼叫
1.多型別傳值和冗餘引數 多型別傳值: def fun(x,y): return x +y print fun(3,5) 8 print fun(*t) 3 def fun(x,y,z): return x + y + z t1 = (1,2,3)
Python中的函式引數【轉載】
原文地址:廖雪峰的官方網站:函式的引數. 定義函式的時候,我們把引數的名字和位置確定下來,函式的介面定義就完成了。對於函式的呼叫者來說,只需要知道如何傳遞正確的引數,以及函式將返回什麼樣的值就夠了,函式內部的複雜邏輯被封裝起來,呼叫者無需瞭解。 Python的函式定義非常簡單,但靈活
python中函式中的實參和形參以及預設引數和收集引數
一.實參和形參 例項:>>> def MyFirstFunction(name): ”函式定義過程中的hame是叫形參“ &nb
C語言:函式中引數的傳值與傳地址
任務程式碼: #include <stdio.h> void swap(int *a ,int *b)//按之前對指標認識,*a代表指標變數a,a儲存的是地址,*a是地址的值。 { //但是可以看到下面傳輸過程中swap(
js拼接字串中含有帶空格的引數的函式(對前一篇的補充)
針對前一篇的例子,有的時候會偷個小懶,會寫成如下程式碼: "<a href=javascript:getProductDetail('"+result[i].spec+"','"+result[i].name+"')>" &