JavaScript函數究竟是值傳遞還是引用傳遞?打賞

很多人認為 JavaScript中函數進行參數傳遞有兩種方式:基礎類型值傳遞;對象類型按引用傳遞。很長一段時間我也這樣認為,其實都是一種值傳遞。

事情是在近期QQ群里偶爾聊到,JavaScript函數傳值到底是值傳遞還是引用傳遞,看到有人說都是值,原因即使是對象也是傳了對象的拷貝,即對象的值本身。本著對技術的刨根問底兒的精神,查了相關資料,得到結論:ECMAScript中所有函數的參數都是按值來傳遞的

下面是一些相關概念的解釋,整理自網絡:

眾所周知,在JavaScript中數據類型可以分為兩類:

原始數據類型值 primitive type,比如Undefined,Null,Boolean,Number,String。

引用類型值,也就是對象類型 Object type,比如Object,Array,Function,Date等。

聲明變量時不同的內存分配

原始值:存儲在棧(stack)中的簡單數據段,也就是說,它們的值直接存儲在變量訪問的位置。這是因為這些原始類型占據的空間是固定的,所以可將他們存儲在較小的內存區域 – 棧中。這樣存儲便于迅速查尋變量的值。

引用值:存儲在堆(heap)中的對象,也就是說,存儲在變量處的值是一個指針(point),指向存儲對象的內存地址。這是因為:引用值的大小會改變,所以不能把它放在棧中,否則會降低變量查尋的速度。相反,放在變量的棧空間中的值是該對象存儲在堆中的地址。地址的大小是固定的,所以把它存儲在棧中對變量性能無任何負面影響。

ct_js_value

不同的內存分配機制也帶來了不同的訪問機制

在javascript中是不允許直接訪問保存在堆內存中的對象的,所以在訪問一個對象時,首先得到的是這個對象在堆內存中的地址,然后再按照這個地址去獲得這個對象中的值,這就是傳說中的按引用訪問。而原始類型的值則是可以直接訪問到的。

復制變量時的不同

原始值:在將一個保存著原始值的變量復制給另一個變量時,會將原始值的副本賦值給新變量,此后這兩個變量是完全獨立的,他們只是擁有相同的value而已。

引用值:在將一個保存著對象內存地址的變量復制給另一個變量時,會把這個內存地址賦值給新變量,也就是說這兩個變量都指向了堆內存中的同一個對象,他們中任何一個作出的改變都會反映在另一個身上。(這里要理解的一點就是,復制對象時并不會在堆內存中新生成一個一模一樣的對象,只是多了一個保存指向這個對象指針的變量罷了)

參數傳遞的不同

首先我們應該明確一點:ECMAScript中所有函數的參數都是按值來傳遞的。但是為什么涉及到原始類型與引用類型的值時仍然有區別呢,還不就是因為內存分配時的差別。 (我對比了一下,這里和復制變量時遵循的機制完全一樣的嘛,你可以簡單地理解為傳遞參數的時候,就是把實參復制給形參的過程)

原始值:只是把變量里的值傳遞給參數,之后參數和這個變量互不影響。

引用值:對象變量它里面的值是這個對象在堆內存中的內存地址,這一點你要時刻銘記在心!因此它傳遞的值也就是這個內存地址,這也就是為什么函數內部對這個參數的修改會體現在外部的原因了,因為它們都指向同一個對象呀。或許我這么說了以后你對書上的例子還是有點不太理解,那么請看圖吧:

所以,如果是按引用傳遞的話,是把第二格中的內容(也就是變量本身)整個傳遞進去(就不會有第四格的存在了)。但事實是變量把它里面的值傳遞(復制)給了參數,讓這個參數也指向原對象。因此如果在函數內部給這個參數賦值另一個對象時,這個參數就會更改它的值為新對象的內存地址指向新的對象,但此時原來的變量仍然指向原來的對象,這時候他們是相互獨立的;但如果這個參數是改變對象內部的屬性的話,這個改變會體現在外部,因為他們共同指向的這個對象被修改了呀!來看下面這個例子吧:(傳說中的call by sharing)

/* obj1仍然指向原來的對象,之所以value改變了,
 *是因為change里的第一條語句,這個時候obj是指向obj1的 .
 *如果是按引用傳遞的話,這個時候obj1.value應該是等于'222'的
*/
var obj1 = {
  value:'111'
};
 
var obj2 = {
  value:'222'
};
 
function change(obj){
  obj.value = '333';
  obj = obj2;
  return obj.value;
}
 
 
var foo = changeStuff(obj1);
 
console.log(foo);// '222' 參數obj指向了新的對象obj2
console.log(obj1.value);//'333'

由此可見,大部分時間,使人們誤解的引用傳遞可能是由于對底層概念的定義理解有誤,錯把值類型和引用類型用到參數傳值上面。

參考:

JavaScript函數究竟是值傳遞還是引用傳遞?
文章《JavaScript函數究竟是值傳遞還是引用傳遞?》二維碼
  • 微信打賞
  • 支付寶打賞

已有1條評論

  1. 電商培訓

    [鐘] 新手~學習起來~~~~~

    2016-03-25 12:16 回復

(必填)

(必填)

(可選)

黑龙江22选5开奖