值傳遞應該是JS最基本的一個知識點了,網上也有不少說法,有按值傳遞,有按引用傳遞,還有按共享傳遞。what?javascript
我一直認爲,學習應該去刨根問底。抓住他的核心點,找到事物的本質。因此在這裏重新給你們梳理下。java
下面我先說下個人結論:學習
傳遞只有一種,就是
按值傳遞
按值傳遞
按值傳遞
,重要的事情要講三遍哦。ui
標準規定,JavaScript 有 6種 基本類型,string
number
boolean
null
undefined
symbol
和Object
類型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 。
經過以上內容是否是就完全搞清楚了值傳遞究竟是怎麼回事了。全部的傳遞方式其實都是按值傳遞,只不過有的值是基本類型,有的值是內存地址。
咱們再來延伸一下,ES6 出了一個新的聲明變量的方式 const
。它能夠聲明一個常量,而且不能從新聲明。也不能修改值。
咱們來看下:
const a = 100;
a = 200; // error
const b = {x:100}
b = {} //error
b.x = 200; //修改爲功
複製代碼
咱們經過今天的內存只是來分析下:
其實上const
鎖死的是變量 a
,你在聲明賦值以後他就鎖定了那一塊棧區的內存。當你賦值的時候其實就是換一塊棧區內存空間,因此修改是無效的。
可是若是初始化值是一個對象,咱們知道在棧區它是一個內存地址。雖然咱們沒法修改棧區,可是咱們能夠修改地址對應的堆區的內容。這也是最後b.x = 200
可以修改爲功的緣由。
當若是再有人問你 值傳遞
引用傳遞
的時候,你能夠大聲的告訴他,只有一種傳遞,值傳遞
囉裏囉嗦的寫了一堆,文筆很差望見諒。若是有錯誤或者不足之處,但願你們指正。若是你讀了以後,對你有一點點的幫助,不甚榮幸。