標籤:alt 不同 存在 ret count arguments href png object
也許大家對於函數的參數都不會太在意,簡單來說,把函數外部的值複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣。深入研究,你會發現其實沒那麼簡單,這個傳參是要分倆種情況(其實這是個錯誤的說法,ECMAScript中所有函數的參數都是按值傳遞的——《高程3》原話,之所以這裡說倆種,是因為結合引用傳參更容易理解)—— 值傳參和引用傳參。
值傳參針對基本類型,引用傳參針對參考型別,傳參可以理解為複製變數值。基本類型複製後倆個變數完全獨立,之後任何一方改變都不會影響另一方;參考型別複製的是引用(即指標),之後的任何一方改變都會映射到另一方。
不少人對參數都是按值傳遞的感到困惑,因為訪問變數有按值和按引用兩種方式。下面就來看看有何不同:
這一段很重要:我們可以把ECMAScript函數的參數想象成局部變數。在向參數傳遞基本類型的值時,被傳遞的值被複製給一個局部變數(即具名引數,或者用ECMAScript的概念來說,就是arguments對象中的一個元素)。在向參數傳遞參考型別時,會把這個值在記憶體中的地址(指標)複製給一個局部變數,因此這個局部變數的變化會反映在函數的外部。
1、按值傳遞
1 function addTen(num) {2 num += 10;3 return num;4 }5 6 var count = 20;7 var result = addTen(count); //按值傳遞 num = count8 alert(count); // 20, 沒變化9 alert(result); // 30
很好理解,因為是按值傳遞的,傳遞完後倆個變數各不相干!
2、按引用傳遞(這麼叫便於理解,其實也是按值傳遞)
1 function setName(obj) {2 obj.name = "Nicholas";3 }4 5 var person = new Object();6 setName(person); //相當於按值傳遞 obj = person7 alert(person.name); // "Nicholas"
當 var person = new Object(); 時,可以用表示變數和對象的關係:
當調用函數 setName(person); 時,可以表示全域變數person和局部變數obj的關心:
以上代碼中建立一個對象,並將其儲存在變數person中。然後,這個變數被傳遞到setName(obj)函數中之後就被複製給了obj。在這個函數內部,obj和person引用的是同一個對象。換句話說,即使ECMAScript說這個變數時按值傳遞的,但obj也會按引用來訪問同一個對象。於是,在函數內部為obj添加name屬性後,函數外部的person也將有所反應;因為這時的person和obj指向同一個堆記憶體位址。所以,很多人錯誤的認為:在局部範圍中修改的對象會在全域對象中反映出來,就說明參數是按引用傳遞的。
為了證明對象也是按值傳遞的,我們再來看看下面這個經過修改的例子:
1 function setName(obj) {2 obj.name = "Nicholas";3 obj = new Object(); //改變obj的指向,此時obj指向一個新的記憶體位址,不再和person指向同一個4 obj.name = "Greg";5 }6 7 var person = new Object();8 setName(person); //你看看下面,相信我也是按值傳遞的了吧9 alert(person.name); //"Nicholas"
當建立obj對象 obj = new Object(); 時,來看看這時person和obj的關係圖:
這個例子與前一個唯一的區別,就是setName()函數中添加了兩行代碼: obj = new Object(); 用來改變obj的指向; obj.name = "Greg"; 用來給新建立的obj添加屬性。如果是按引用傳遞的,那麼person就會自動被修改為指向新建立的obj的記憶體位址,則person的name屬性值被修改為"Greg"。但是,當訪問person.name時,顯示的結果為"Nicholas"。這說明即使在函數內部修改了參數的值,但原始的引用仍然保持未變。實際上,當在函數內部重寫obj時,這個變數引用的就是一個局部對象了。而這個局部對象會在函數執行完畢後被立即銷毀!
雖然變數person和參數obj的值一樣都是同一個對象在記憶體中的地址,但它們是兩個相互獨立的變數。如果在函數中改變參數obj的值,使其指向記憶體中另外一個對象,變數person的值不會改變,還是指向原來的對象。
因此JavaScript中函數的參考型別值參數的傳遞是按值傳遞的。
js函數傳參