傳遞只有一種 —— 按值傳遞

值傳遞應該是JS最基本的一個知識點了,網上也有不少說法,有按值傳遞,有按引用傳遞,還有按共享傳遞。what?javascript

先說結論

我一直認爲,學習應該去刨根問底。抓住他的核心點,找到事物的本質。因此在這裏重新給你們梳理下。java

下面我先說下個人結論:學習

傳遞只有一種,就是 按值傳遞 按值傳遞 按值傳遞,重要的事情要講三遍哦。ui

數據類型

標準規定,JavaScript 有 6種 基本類型,string number boolean null undefined symbolObject類型spa

咱們首先來看下,這七種類型在內存中是怎麼分配的。3d

堆棧結構

內存是分爲棧區和堆區的code

當咱們聲明6種基本類型的時候,就是在棧區開闢一段空間。cdn

當咱們聲明一個Object類型的時候,在堆區和棧區各分配一段空間,堆區是Object聲明的實體,棧區存放的是指向堆區的地址。對象

知識延伸

標準裏面規定了,全部基本類型的值都是不可改變的。blog

var a = 1;

a = 2;
複製代碼

你可能說不對吧,上面的代碼,a就從1變成2了。

對,上面的變量a,確實變了。要理解上面那句話,咱們就須要明白 基本類型值自己 和 一個被賦值基本類型的變量的區別。值不可更改,變量能夠從新賦值。

下面咱們看一下,當咱們賦值的時候,內存中是怎麼工做的。

當咱們聲明 a 而且賦值爲 1 的時候,棧區分配一段空間,值爲1

當咱們賦值爲2的時候,並不會修改 1 所在空間,而是重新分配一段空間,值爲 2,而且把這個賦值給變量 a

值傳遞

上面的東西咱們都明白了,如今咱們再來看看按值傳遞是怎麼回事。

第一種情形

var a = 1;
function getNum(p){
    p = 10;
    return p;
}
getNum(a) // 10
a  // 1
複製代碼

執行方法的時候,會把 a 的值,複製一份傳遞給形參 p

因爲 a 的值是 1 ,因此 p 的值也是 1

第二種情形

var a = {
    x: 1
}
function getNum(p){
    p.x = 10;
    console.log(p.x) // 10
}
getNum(a) 
a.x  // 10
複製代碼

以上代碼也是把 a 的值複製一份給 p

只不過 a 的值比較特殊,他是一個指向堆區的內存地址,因此p的值也是一個指向同一個堆區的地址。

因此操做 p 的時候 a 也會跟着變化。由於這是在操做同一分內存。

第三種情形

var a = {
    x: 1
}
function getNum(p){
    p = 10;
    console.log(p) // 10
}
getNum(a) 
a.x  // 1
複製代碼

這個跟第二種也有點像,也是 a 的內存地址複製了一份給 p

區別是對變量 p 重新賦值了。因此他的修改其實不會影響到 a

擴展 const

經過以上內容是否是就完全搞清楚了值傳遞究竟是怎麼回事了。全部的傳遞方式其實都是按值傳遞,只不過有的值是基本類型,有的值是內存地址。

咱們再來延伸一下,ES6 出了一個新的聲明變量的方式 const。它能夠聲明一個常量,而且不能從新聲明。也不能修改值。

咱們來看下:

const a = 100;
a = 200;  // error

const b = {x:100}
b = {} //error
b.x = 200; //修改爲功
複製代碼

咱們經過今天的內存只是來分析下:

其實上const 鎖死的是變量 a,你在聲明賦值以後他就鎖定了那一塊棧區的內存。當你賦值的時候其實就是換一塊棧區內存空間,因此修改是無效的。

可是若是初始化值是一個對象,咱們知道在棧區它是一個內存地址。雖然咱們沒法修改棧區,可是咱們能夠修改地址對應的堆區的內容。這也是最後b.x = 200可以修改爲功的緣由。

最後

當若是再有人問你 值傳遞 引用傳遞 的時候,你能夠大聲的告訴他,只有一種傳遞,值傳遞

囉裏囉嗦的寫了一堆,文筆很差望見諒。若是有錯誤或者不足之處,但願你們指正。若是你讀了以後,對你有一點點的幫助,不甚榮幸。

參考連接

developer.mozilla.org/zh-CN/docs/…

相關文章
相關標籤/搜索