一文詳解JavaScript中的按值傳遞和按引用傳遞
JavaScript中幾乎都是按值傳遞
編程語言中,把一個(gè)變量的值賦值給另一個(gè)變量,或者給函數(shù)調(diào)用傳遞參數(shù)有兩種方式:按值傳遞和按引用傳遞。
JavaScript中幾乎都是按值傳遞。我們看一個(gè)例子:
let a = 1 let b = a b = 2 console.log(a) // 1
- 上面的代碼,聲明了一個(gè)變量
a
,賦值為1; - 然后又聲明了一個(gè)變量
b
,將變量a
的值1賦值給變量b
,此時(shí)變量b
的值也是1; - 接著我們將變量
b
的值修改為2; - 此時(shí)打印變量
a
的值應(yīng)該仍然是1,而不是2。
這就是按值傳遞,我們把變量a
的值賦值給變量b
的時(shí)候,只是把1這個(gè)值復(fù)制了一份給變量b
,變量b
的值的修改并不會(huì)影響到變量a
的值。
很好,到目前為止,我們說上面的代碼是按值傳遞很好理解,很符合我們的直覺。
上面是基元值的情況,如果換成引用類型的值呢?看下面的代碼。
const foo = { a: 1 } const bar = foo bar.a = 2 console.log(foo.a) // 2
- 上面的代碼聲明了一個(gè)變量
foo
,給它賦值了一個(gè)對(duì)象; - 然后又聲明了一個(gè)變量
bar
,把變量foo
指向的對(duì)象賦值給變量bar
; - 接著我們通過
bar.a
把對(duì)象的屬性a
修改為2; - 我們發(fā)現(xiàn)
foo.a
也被修改了!
說好的按值傳遞呢?如果是按值傳遞,修改bar.a
不應(yīng)該導(dǎo)致foo.a
被修改啊,這好像不太符合直覺???難道引用類型的值是按引用傳遞嗎?
并不是。JavaScript中引用類型的值也是按值傳遞的,只不過這個(gè)傳遞的值是對(duì)象在堆內(nèi)存中的地址。
看上面的圖片可以更清楚地理解這個(gè)過程,假設(shè)對(duì)象在堆內(nèi)存中的地址是0x100,那么按值傳遞的就是0x100這個(gè)地址。bar.a
修改了對(duì)象里屬性的值,但是foo
和bar
仍都然都指向地址0x100,所以通過bar.a
修改對(duì)象屬性值會(huì)反應(yīng)到foo.a
上。
上面的圖只是一個(gè)粗略的方便理解的圖,下面的圖可能更符合代碼實(shí)際的內(nèi)存分布。
另外,仍然是上面的代碼,如果我們稍加改動(dòng),給變量bar
賦值一個(gè)新的對(duì)象,那么變量foo
和變量bar
就指向不同的內(nèi)存地址了,修改變量bar
將不再導(dǎo)致變量foo
被修改。有些支持按引用傳遞的語言,類似的操作會(huì)導(dǎo)致變量foo
也被修改,這個(gè)我不太了解,所以就不展開了。
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(實(shí)時(shí)綁定),這是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的變量是只讀的,不能修改,嘗試修改會(huì)報(bào)錯(cuò) TypeError: Assignment to constant variable. increment() console.log(count) // ?
讓我們暫停下來,思考一下,上面的代碼中,第二個(gè)console.log(count)
會(huì)輸出什么?
答案是2。ES Module中export
的變量,其它模塊import
進(jìn)來之后是只讀的,嘗試修改會(huì)報(bào)錯(cuò)。但是export
變量的模塊可以另外導(dǎo)出一個(gè)方法用來修改這個(gè)變量,變量的修改會(huì)同步反應(yīng)在兩個(gè)模塊中,這種情況被稱為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,因?yàn)檫@里count
是按值傳遞的。
總結(jié)
- JavaScript中幾乎都是按值傳遞。
- ES Module中export導(dǎo)出的變量是JavaScript中唯一的按引用傳遞,這被稱作live bindings。另外export導(dǎo)出的變量是只讀的,在模塊外部不允許修改它的值,通??梢灶~外導(dǎo)出一個(gè)方法用來修改這個(gè)變量。
以上就是一文詳解JavaScript中的按值傳遞和按引用傳遞的詳細(xì)內(nèi)容,更多關(guān)于JavaScript按值和按引用傳遞的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript實(shí)現(xiàn)的開關(guān)燈泡點(diǎn)擊切換特效示例
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的開關(guān)燈泡點(diǎn)擊切換特效,涉及javascript事件響應(yīng)及頁面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-07-0720行JS代碼實(shí)現(xiàn)網(wǎng)頁刮刮樂效果
下面小編就為大家?guī)硪黄?0行JS代碼實(shí)現(xiàn)網(wǎng)頁刮刮樂效果。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06JS addEventListener()和attachEvent()方法實(shí)現(xiàn)注冊(cè)事件
這篇文章主要介紹了JS addEventListener()和attachEvent()方法實(shí)現(xiàn)注冊(cè)事件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01JavaScript控制網(wǎng)頁層收起和展開效果的方法
這篇文章主要介紹了JavaScript控制網(wǎng)頁層收起和展開效果的方法,涉及javascript操作網(wǎng)頁元素動(dòng)態(tài)效果的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04JavaScript 創(chuàng)建隨機(jī)數(shù)和隨機(jī)圖片
關(guān)于javascript隨機(jī)數(shù)的,很早以前的文章了,不過內(nèi)容還是不錯(cuò)的,如果想要更多的效果,可以去腳本之家搜下。2009-12-12Javascript將字符串日期格式化為yyyy-mm-dd的方法
日期格式化相信對(duì)于大家來說再熟悉不過,最近工作中自己利用Javascript就寫了一個(gè),現(xiàn)在將實(shí)現(xiàn)的代碼分享給大家,希望對(duì)有需要的朋友們能有所幫助,感興趣的朋友們下面來一起看看吧。2016-10-10原生JS實(shí)現(xiàn)網(wǎng)絡(luò)彩票投注效果
分享一個(gè)最近模仿市面彩票系統(tǒng)寫個(gè)小案例,沒有使用任何后臺(tái),從投注到開獎(jiǎng)再到返獎(jiǎng)都是用原生JS實(shí)現(xiàn)的。2016-09-09