標籤:
變數類型
瞭解參數的傳遞之前我們來複習下變數的類型,JavaScript中的變數有5個基礎資料型別 (Elementary Data Type)(Undefined, Null, Boolean, Number, String)和引用資料類型(Object,Function,Array等)。
基本類型和參考型別的區別
// 聲明一個String類型的變數
var str = "string";
// 聲明一個參考型別的變數,並添加屬性
var person = new Object();person.name = "Jeremy";
二者的區別主要在於對變數內容儲存的方式,基本類型的變數中儲存的就是簡單的資料區段,而參考型別變數儲存的是指向對象的引用,比如:
// 基本類型的變數複製,可以看出基本類型變數儲存的就是變數的值
var num1 = 5;var num2 = num1;console.log(num2); //5
num1的5與num2的5是完全獨立的,這兩個變數可以參與任何操作而不會相互影響。能夠形象的展示複製過程。
// 參考型別的變數複製,可以看出引用變數中儲存的是指向對象的引用
// ObjectObject Storage Service於堆中,而obj1和obj2分別儲存了指向此Object對象的引用
var obj1 = new Object();obj1.name = "Jeremy";var obj2 = obj1;obj2.name = "James";console.log(obj1.name); //James
首先變數obj1儲存了一個對象的新執行個體,又給obj1添加一個新屬性name,後obj1對象被複製給了obj2,obj2也有了name這個屬性,並且訪問的地址是跟obj1的name屬性是一個地址,所以當修改了obj2的那麼屬性的話,那obj1的name屬性也會改變。展示了儲存在變數對象中的變數和儲存在堆中的對象之間的這種關係。
參數傳遞
在JavaScript中無論是基本類型還是參考型別,函數參數都是按值傳遞的,先來看基本類型:
function test(num) { num += 10; return num;}var num = 10;var res = test(num);console.log(num); //10 外部變數並未受到影響console.log(res); //20
接下來看參考型別:
function setName(obj) { obj.name = "James";}var person = new Object();person.name = "Jeremy";setName(person);
console.log(person.name);//James 影響到了外部參考變數
?乍一看,這不就是按引用傳遞嗎?怎麼會是按值傳遞呢?之所以是按值傳遞是因為當調用setName(person)的時候,實際上是把person所指向的對象的引用進行了複製,然後傳遞給了setName函數,這樣在函數setName內部對此引用進行操作時候是會影響到此引用所指向的對象,即外部person所指向的對象。
總的來說,基本類型的參數傳遞複製的是具體的值,而參考型別的參數傳遞複製的是這個引用變數儲存的對對象的引用。
為了進一步證明參考型別的參數傳遞是按值傳遞而不是按引用傳遞的,請看:
function setName(obj) { obj.name = "James"; obj = new Object(); obj.name = "Leon"}var person = new Object();person.name = "Jeremy";setName(person);console.log(person.name);//James
以上代碼輸出的是James,如果是按引用傳遞,那麼以上代碼輸出的是Leon。實際上,當執行obj.name = "James"的時候,引用所指向的對象的值已經發生了改變,當在對obj進行覆蓋的時候,obj的值是一個指向局部對象的引用,而這個引用無法對外部的對象產生影響,並且此對象會在函數執行結束之後銷毀。
JavaScript中參數的傳遞