轉: https://segmentfault.com/a/1190000005177386javascript
衆所周知,JavaScript中參數是按值傳遞的。與訪問變量不一樣,基本類型和引用類型的參數在傳遞時都如同變量的複製。java
可是咱們在使用引用類型的參數傳遞時,常常會發如今函數內改變引用類型參數(如對象)會在函數外反映出來,這種狀況貌似與「按值傳參」的思想不符?
我本人在這個坑上也摔過不少次,最近遇到了一個新詞:call by sharing(按共享傳參)讓我對這個問題有了比較深入的認識。分享給對這個問題有誤解的童鞋們。。。
先大概介紹按值傳參segmentfault
基本類型的參數傳遞比較簡單,示例代碼app
function add(num){ num+=10; console.log(num); } var str=10; add(str);//20 console.log(str);//10
str的值複製給了函數add內部的局部變量num,因此在函數內部改變num的值並不會影響外部str的值。less
紅寶書上有這麼一句話:在向參數傳遞引用類型的值時,會把這個值在內存中的地址複製給一個局部變量,所以這個局部變量的變化會反應函數外。ide
用兩段代碼來講明:函數
function setName1(obj){ obj.name="Mike"; return obj; } var person=new Object(); setName1(person); console.log(person.name);//'Mike'
這段代碼表面上看:函數內部的改變影響了函數外,難道是按引用傳遞?再看下面這段代碼:ui
function setName2(obj){ obj.name="Mike"; obj={name:"Tom"}; return obj; } var person=new Object(); setName2(person); console.log(person.name);//'Mike'
這個狀況就比較有趣了,若是是按引用傳遞的,函數內函數外始終訪問用一個引用,最後的結果應該是「Tom」纔對。this
再回到以前提到的:在向參數傳遞引用類型的值時,會把這個值在內存中的地址複製給一個局部變量,所以這個局部變量的變化會反應函數外。
其實這句話從另外一個角度講,就是call by sharing(共享傳參)的定義。spa
先看一下ECMAScript中對call by sharing的定義
The main point of this strategy is that function receives the copy of the reference to object. This reference copy is associated with the formal parameter and is its value.
Regardless the fact that the concept of the reference in this case appears, this strategy should not be treated as call by reference (though, in this case the majority makes a mistake), because the value of the argument is not the direct alias, but the copy of the address.
The main difference consists that assignment of a new value to argument inside the function does not affect object outside (as it would be in case of call by reference). However, because formal parameter, having an address copy, gets access to the same object that is outside (i.e. the object from the outside completely was not copied as would be in case of call by value), changes of properties of local argument object — are reflected in the external object.
其實這段話,特別是標粗的地方說明的就是:引用類型把在內存中的地址複製給了函數中的局部變量。
因此出現會兩種狀況:
改變引用類型的屬性
當在函數中改變引用類型(如對象)的屬性時,是在同一個內存地址區域進行操做,因此會在函數外反映出來。如setName1
列表項目在函數內,對形參進行了從新複製,即改變了形參的引用,(內存中的地址已經改變),與實參引用已經徹底不同了,因此不會對函數外引用類型變量參數產生影響,如setName2.