<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
現代的前端開發,不再是刀耕火種的 JQ 時代,而是 MVVM ,元件化,工程化,承載著日益複雜的業務邏輯。記憶體消耗和效能問題,成為當代開發者必須要考慮的問題。
本文從堆疊記憶體講起,讓大家理解JS中變數的記憶體使用以及變動情況 。
先初步瞭解JS中的堆和棧,記憶體空間分為 堆和棧 兩個區域,程式碼執行時,解析器會先判斷變數型別,根據變數型別,將變數放到不同的記憶體空間中(堆和棧)。
如圖所示
基本的資料型別(String,Number,Boolean,Null,Undefined, Symbol)都會分配棧區。它的值是存放在棧中的簡單資料段,資料大小確定,記憶體空間大小可以分配;按值存放,所以可以按值存取。
參照資料型別 Object (物件)的變數都放到堆區。它在棧記憶體中儲存的實際上是物件在堆記憶體中的參照地址, 通過這個參照地址可以快速查詢到儲存在堆記憶體中的物件。存放在堆記憶體中的物件,每個空間大小不一樣,要根據情況進行特定的設定。
如下程式碼範例:
var a = 12; var b = false; var c = 'string' var obj = { name: 'sunshine' }
棧區的特點:空間小,資料型別簡單,讀寫速度快,一般由JS引擎自動釋放
堆區的特點:空間大,資料型別複雜,讀寫速度稍遜,當物件不在被參照時,才會被週期性的回收。
瞭解了記憶體的棧區和堆區後, 接下來,來看看變數如何在棧區和堆區“愉快的玩耍”。
下面來看一組基本型別的變數傳遞的例子:
let a = 100 let b = a a = 200 console.log(b) // 100
初始棧中 a 的值為100;其次棧區中新增 b,並且將a複製了一份給b;最後 a儲存了另外一個值 200,而b的值不會改變。
再來看一組參照型別傳遞的例子:
let obj1 = { name: 'a' } let obj2 = obj1 obj2.name = 'b' console.log(obj1.name) // b
以上程式碼中,obj1 和 obj2 指向了同一個堆記憶體,obj1 賦值給 obj2,實際上這個堆記憶體物件在棧記憶體的參照地址複製了一份給了 obj2,所以 obj1 和 obj2 指標都指向堆記憶體中的同一個。
圖解如下:
綜合案例:
var a = [1, 2, 3, 4] var c = a[0] // 這時變數c是基本資料型別,儲存在棧記憶體中;改變棧中的資料不會影響堆中的資料 c = 5 console.log(c) // 5 console.log(a[0]) // 1 let b = a // b是參照資料型別,棧記憶體指標和 a一樣都指向同一個堆記憶體,改變數值後,會影響堆中的資料 b[2] = 6 console.log(a[2]) // 6
劃重點:在JS的變數傳遞中,本質上都可以看成是值傳遞,只是這個值可能是基礎資料型別,也可能是一個參照地址,如果是參照地址,我們通常就說為參照傳遞。JS中比較特殊,不能直接操作物件的記憶體空間,必須通過指標(所謂的參照)來存取。
所以,即使是所有複雜資料型別(物件)的賦值操作,本質上也是值傳遞。在往下看一下不同的值在引數中是如何傳遞的。
由上可知,ECMAScript中所有函數的引數都是按值傳遞的。這意味著函數外的值會被複制到函數內部的引數中,就像從一個變數賦值到另一個變數一樣。在按值傳遞引數時,值會被複制到一個區域性變數(arguments物件中的一個槽位)。在按參照傳遞引數時,值在記憶體中的位置會被儲存在一個區域性變數,這意味著對本地變數的修改會反映到函數外部。
下面看一個例子:在 bar 函數中,當引數為基本資料型別時,函數體內會賦值一份引數值,而不會影響原引數的實際值。
let foo = 1 const bar = value => { // var value = foo value = 2 console.log(value) } bar(foo) // 2 console.log(foo) // 1
如果將函數參改為參照型別,結果就不一樣了:
let foo = { bar: 1} const func = obj => { // var obj = foo obj.bar = 2 console.log(obj.bar) } func(foo) // 2 console.log(foo.bar) // 2
從以上程式碼中可以看出,如果函數引數是一個參照型別的資料,那麼當在函數體內修改這個參照型別引數的某個屬性時,也將對原來的引數進行修改,因為此時函數體內的參照地址指向了原來的引數。
但是,如果在函數體內直接修改對引數的參照,則情況又會不一樣:
let foo = { bar: 1} const func = obj => { // var obj = 2 obj = 2 console.log(obj) } func(foo) // 2 console.log(foo) // { bar: 1 }
這是因為如果我們將一個已經賦值的變數重新賦值,那麼它將包含新的資料或參照地址。這時函數體內新建立了一個參照,任何操作都不會影響原引數的實際值。
如果一個物件沒有被任何變數指向,JavaScript引擎的垃圾回收機制會將該物件銷燬並釋放記憶體。
function func (person) { person.age = 25 person = { age: 50 } return person } var person1 = { age: 30 } var person2 = func(person1); console.log(person1) console.log(person2)
答案:{ age: 25 },{ age: 50 }。因為函數內部,person 第一次修改,相當於 複製了 person1 的記憶體地址給person,第二次修改是建立一個新的 person 變數。所以 person1 在堆記憶體中的值會被修改,person 也是新的 person 變數返回的值
let obj1 = { x: 100, y: 200} let obj2 = obj1 let x1 = obj1.x obj2.x = 101 x1 = 102 console.log(obj1)
答案:{ x: 101, y: 200 },x1是干擾項,因為obj.x是原始型別值,所以修改後不會影響原資料的參照地址。
舉個例子:
值傳遞:A覺得B的房子裝修風格很好,於是借用了B的裝修風格。但是過了段時間A給房子裡面又新增了點別的風格,但是B的房子風格還是原來的。
參照傳遞:A喜歡B的房子風格,借用了人家的風格,過了段時間A給家裡新增了新的風格,但是A覺得自己的風格比B的好,於是通過B給A的地址,去B的家硬是把人家的風格改成和自己一樣的了。
到此這篇關於JS中"值傳遞"和"參照傳遞"的文章就介紹到這了,更多相關JS 值傳遞和參照傳遞內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45