JS中函數參數值傳遞和引用傳遞

  也許你們對於函數的參數都不會太在乎,簡單來講,把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。深刻研究,你會發現其實沒那麼簡單,這個傳參是要分倆種狀況(其實這是個錯誤的說法,ECMAScript中全部函數的參數都是按值傳遞的——《高程3》原話,之因此這裏說倆種,是由於結合引用傳參更容易理解)—— 值傳參和引用傳參。 html

  值傳參針對基本類型,引用傳參針對引用類型,傳參能夠理解爲複製變量值。基本類型複製後倆個變量徹底獨立,以後任何一方改變都不會影響另外一方;引用類型複製的是引用(即指針),以後的任何一方改變都會映射到另外一方。函數

  很多人對參數都是按值傳遞的感到困惑,由於訪問變量有按值和按引用兩種方式。下面就來看看有何不一樣:spa

  

  這一段很重要咱們能夠把ECMAScript函數的參數想象成局部變量。在向參數傳遞基本類型的值時,被傳遞的值被複制給一個局部變量(即命名參數,或者用ECMAScript的概念來講,就是arguments對象中的一個元素)。在向參數傳遞引用類型時,會把這個值在內存中的地址(指針)複製給一個局部變量,所以這個局部變量的變化會反映在函數的外部。指針

 

一、按值傳遞

1 function addTen(num) {
2     num += 10;
3     return num;
4 }
5 
6 var count = 20;
7 var result = addTen(count);  //按值傳遞 num = count
8 alert(count);  // 20, 沒變化
9 alert(result);  // 30

  很好理解,由於是按值傳遞的,傳遞完後倆個變量各不相干!code

 

二、按引用傳遞

1 function setName(obj) {
2     obj.name = "Nicholas";
3 }
4 
5 var person = new Object();
6 setName(person);   // obj = person
7 alert(person.name);   // "Nicholas" 看起來是按引用傳遞,但千萬不要覺得是按引用傳遞~~~

   var person = new Object(); 時,能夠用下圖表示變量和對象的關係:htm

  當調用函數 setName(person); 時,下圖能夠表示全局變量person和局部變量obj的關心:對象

  以上代碼中建立一個對象,並將其保存在變量person中。而後,這個變量被傳遞到setName(obj)函數中以後就被複制給了obj。在這個函數內部,obj和person引用的是同一個對象。換句話說,即便ECMAScript說這個變量是按值傳遞的,但obj也會按引用來訪問同一個對象。因而,在函數內部爲obj添加name屬性後,函數外部的person也將有所反應;由於這時的person和obj指向同一個堆內存地址。因此,不少人錯誤的認爲:在局部做用域中修改的對象會在全局對象中反映出來,就說明參數是按引用傳遞的。blog

  

  爲了證實對象也是按值傳遞的,咱們再來看看下面這個通過修改的例子:ip

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"這句話以前說的有誤,引用傳遞的是指針的值,obj=new Object()改寫了本身的指向,並不會影響到person的指向,這種方式就是按引用傳遞。即便不把對象賦值給函數的參數,obj改寫指向對person也沒影響,見下面代碼)。可是,當訪問person.name時,顯示的結果爲"Nicholas"。這說明即便在函數內部修改了參數的值,但原始的引用仍然保持未變。實際上,當在函數內部重寫obj時,這個變量引用的就是一個局部對象了。而這個局部對象會在函數執行完畢後被當即銷燬!

 

推翻以上都是按值傳遞的結論:

var person=new Object(); 
var obj = person;  // 賦值
obj.name="ABC"; 
obj=new Object(); 
obj.name="BCD"; 
console.log(person.name);// ABC  並無影響person的指向

 

  綜上所述,仍是以爲參數傳遞對象時是按引用傳遞的,歡迎指正!

相關文章
相關標籤/搜索