一文詳解JavaScript中的按值傳遞和按引用傳遞
JavaScript中幾乎都是按值傳遞
編程語言中,把一個變量的值賦值給另一個變量,或者給函數(shù)調(diào)用傳遞參數(shù)有兩種方式:按值傳遞和按引用傳遞。
JavaScript中幾乎都是按值傳遞。我們看一個例子:
let a = 1 let b = a b = 2 console.log(a) // 1
- 上面的代碼,聲明了一個變量
a,賦值為1; - 然后又聲明了一個變量
b,將變量a的值1賦值給變量b,此時變量b的值也是1; - 接著我們將變量
b的值修改為2; - 此時打印變量
a的值應(yīng)該仍然是1,而不是2。
這就是按值傳遞,我們把變量a的值賦值給變量b的時候,只是把1這個值復(fù)制了一份給變量b,變量b的值的修改并不會影響到變量a的值。
很好,到目前為止,我們說上面的代碼是按值傳遞很好理解,很符合我們的直覺。
上面是基元值的情況,如果換成引用類型的值呢?看下面的代碼。
const foo = {
a: 1
}
const bar = foo
bar.a = 2
console.log(foo.a) // 2
- 上面的代碼聲明了一個變量
foo,給它賦值了一個對象; - 然后又聲明了一個變量
bar,把變量foo指向的對象賦值給變量bar; - 接著我們通過
bar.a把對象的屬性a修改為2; - 我們發(fā)現(xiàn)
foo.a也被修改了!
說好的按值傳遞呢?如果是按值傳遞,修改bar.a不應(yīng)該導(dǎo)致foo.a被修改啊,這好像不太符合直覺?。侩y道引用類型的值是按引用傳遞嗎?
并不是。JavaScript中引用類型的值也是按值傳遞的,只不過這個傳遞的值是對象在堆內(nèi)存中的地址。

看上面的圖片可以更清楚地理解這個過程,假設(shè)對象在堆內(nèi)存中的地址是0x100,那么按值傳遞的就是0x100這個地址。bar.a修改了對象里屬性的值,但是foo和bar仍都然都指向地址0x100,所以通過bar.a修改對象屬性值會反應(yīng)到foo.a上。
上面的圖只是一個粗略的方便理解的圖,下面的圖可能更符合代碼實際的內(nèi)存分布。

另外,仍然是上面的代碼,如果我們稍加改動,給變量bar賦值一個新的對象,那么變量foo和變量bar就指向不同的內(nèi)存地址了,修改變量bar將不再導(dǎo)致變量foo被修改。有些支持按引用傳遞的語言,類似的操作會導(dǎo)致變量foo也被修改,這個我不太了解,所以就不展開了。
const foo = {
a: 1
}
let bar = foo
bar = {
a: 2
}
console.log(foo.a) // 1

ES Module中的live bindings
前面我們說了,JavaScript中幾乎都是按值傳遞,這樣說通常都有例外。ES Module中export導(dǎo)出的變量被稱為live bindings(實時綁定),這是JavaScript中唯一按引用傳遞的情況。
// a.js
export let count = 1
export function increment() {
count++
}
// b.js
import { count, increment } from './a.js'
console.log(count) // 1
// count = 2 // import的變量是只讀的,不能修改,嘗試修改會報錯 TypeError: Assignment to constant variable.
increment()
console.log(count) // ?
讓我們暫停下來,思考一下,上面的代碼中,第二個console.log(count)會輸出什么?
答案是2。ES Module中export的變量,其它模塊import進(jìn)來之后是只讀的,嘗試修改會報錯。但是export變量的模塊可以另外導(dǎo)出一個方法用來修改這個變量,變量的修改會同步反應(yīng)在兩個模塊中,這種情況被稱為live bindings,是按引用傳遞的。
上面類似的代碼在CommonJs中的執(zhí)行結(jié)果截然不同。
// a.js
let count = 1
function increment() {
count++
}
module.exports = {
count,
increment
}
const { count, increment } = require('./a.js')
console.log(count) // 1
count = 2 // 可以修改
console.log(2) // 2
increment()
console.log(count) // 是2而不是3
require導(dǎo)入的變量是可以被修改的,上面的代碼中最后的console.log(count)的值是2而不是3,因為這里count是按值傳遞的。
總結(jié)
- JavaScript中幾乎都是按值傳遞。
- ES Module中export導(dǎo)出的變量是JavaScript中唯一的按引用傳遞,這被稱作live bindings。另外export導(dǎo)出的變量是只讀的,在模塊外部不允許修改它的值,通??梢灶~外導(dǎo)出一個方法用來修改這個變量。
以上就是一文詳解JavaScript中的按值傳遞和按引用傳遞的詳細(xì)內(nèi)容,更多關(guān)于JavaScript按值和按引用傳遞的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
javascript forEach通用循環(huán)遍歷方法
循環(huán)遍歷一個元素是開發(fā)中最常見的需求之一,那么讓我們來看一個由框架BASE2和Jquery的結(jié)合版本吧.2010-10-10
JS學(xué)習(xí)筆記之原型鏈和利用原型實現(xiàn)繼承詳解
這篇文章主要介紹了JS學(xué)習(xí)筆記之原型鏈和利用原型實現(xiàn)繼承,結(jié)合實例形式詳細(xì)分析了javascript原型鏈以及利用原型實現(xiàn)繼承的相關(guān)操作技巧與注意事項,需要的朋友可以參考下2019-05-05
js對字符串和數(shù)字進(jìn)行加法運算的一些情況
這篇文章主要介紹了js對字符串和數(shù)字進(jìn)行加法運算的一些情況,需要的朋友可以參考下2023-02-02
JS實現(xiàn)兩個跨域頁面實現(xiàn)量子糾纏互動效果
這篇文章主要為大家詳細(xì)介紹了如何利用JavaScript實現(xiàn)兩個跨域頁面實現(xiàn)量子糾纏互動效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12
JavaScript字符串_動力節(jié)點Java學(xué)院整理
JavaScript中的字符串就是用''或""括起來的字符表示。下面通過本文給大家介紹JavaScript字符串的相關(guān)知識,感興趣的朋友一起看看吧2017-06-06

