成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

JavaScript 是如何工作的:JavaScript 的內(nèi)存模型

baoxl / 3631人閱讀

摘要:調(diào)用堆棧是存放原始數(shù)據(jù)類型的地方除了函數(shù)調(diào)用之外。上一節(jié)中聲明變量后調(diào)用堆棧的粗略表示如下。解釋改變的正確方法是更改內(nèi)存地址。在聲明時(shí),將在調(diào)用堆棧上分配內(nèi)存地址,該值是在堆上分配的內(nèi)存地址。

這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 21 篇。

想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!

如果你錯(cuò)過了前面的章節(jié),可以在這里找到它們:

JavaScript 是如何工作的:引擎,運(yùn)行時(shí)和調(diào)用堆棧的概述!

JavaScript 是如何工作的:深入V8引擎&編寫優(yōu)化代碼的5個(gè)技巧!

JavaScript 是如何工作的:內(nèi)存管理+如何處理4個(gè)常見的內(nèi)存泄漏!

JavaScript 是如何工作的:事件循環(huán)和異步編程的崛起+ 5種使用 async/await 更好地編碼方式!

JavaScript 是如何工作的:深入探索 websocket 和HTTP/2與SSE +如何選擇正確的路徑!

JavaScript 是如何工作的:與 WebAssembly比較 及其使用場景!

JavaScript 是如何工作的:Web Workers的構(gòu)建塊+ 5個(gè)使用他們的場景!

JavaScript 是如何工作的:Service Worker 的生命周期及使用場景!

JavaScript 是如何工作的:Web 推送通知的機(jī)制!

JavaScript 是如何工作的:使用 MutationObserver 跟蹤 DOM 的變化!

JavaScript 是如何工作的:渲染引擎和優(yōu)化其性能的技巧!

JavaScript 是如何工作的:深入網(wǎng)絡(luò)層 + 如何優(yōu)化性能和安全!

JavaScript 是如何工作的:CSS 和 JS 動(dòng)畫底層原理及如何優(yōu)化它們的性能!

JavaScript 是如何工作的:解析、抽象語法樹(AST)+ 提升編譯速度5個(gè)技巧!

JavaScript 是如何工作的:深入類和繼承內(nèi)部原理+Babel和 TypeScript 之間轉(zhuǎn)換!

JavaScript 是如何工作的:存儲(chǔ)引擎+如何選擇合適的存儲(chǔ)API!

JavaScript 是如何工作的:Shadow DOM 的內(nèi)部結(jié)構(gòu)+如何編寫?yīng)毩⒌慕M件!

JavaScript 是如何工作的:WebRTC 和對(duì)等網(wǎng)絡(luò)的機(jī)制!

JavaScript 是如何工作的:編寫自己的 Web 開發(fā)框架 + React 及其虛擬 DOM 原理!

JavaScript 是如何工作的:模塊的構(gòu)建以及對(duì)應(yīng)的打包工具

// 聲明一些變量并初始化它們
var a = 5
let b = "xy"
const c = true

// 分配新值
a = 6
b = b + "z"
c = false //  類型錯(cuò)誤:不可對(duì)常量賦值

作為程序員,聲明變量、初始化變量(或不初始化變量)以及稍后為它們分配新值是我們每天都要做的事情。

但是當(dāng)這樣做的時(shí)候會(huì)發(fā)生什么呢? JavaScript 如何在內(nèi)部處理這些基本功能? 更重要的是,作為程序員,理解 JavaScript 的底層細(xì)節(jié)對(duì)我們有什么好處。

下面,我打算介紹以下內(nèi)容:

JS 原始數(shù)據(jù)類型的變量聲明和賦值

JavaScript內(nèi)存模型:調(diào)用堆棧和堆

JS 引用類型的變量聲明和賦值

let vs const

JS 原始數(shù)據(jù)類型的變量聲明和賦值

讓我們從一個(gè)簡單的例子開始。下面,我們聲明一個(gè)名為myNumber的變量,并用值23初始化它。

let myNumber = 23

當(dāng)執(zhí)行此代碼時(shí),JS將執(zhí)行:

為變量(myNumber)創(chuàng)建唯一標(biāo)識(shí)符(identifier)。

在內(nèi)存中分配一個(gè)地址(在運(yùn)行時(shí)分配)。

將值 23 存儲(chǔ)在分配的地址。

雖然我們通俗地說,“myNumber 等于 23”,更專業(yè)地說,myNumber 等于保存值 23 的內(nèi)存地址,這是一個(gè)值得理解的重要區(qū)別。

如果我們要?jiǎng)?chuàng)建一個(gè)名為 newVar 的新變量并把 myNumber 賦值給它。

let newVar = myNumber

因?yàn)?myNumber 在技術(shù)上實(shí)際是等于 “0012CCGWH80”,所以 newVar 也等于 “0012CCGWH80”,這是保存值為23的內(nèi)存地址。通俗地說就是 newVar 現(xiàn)在的值為 23

因?yàn)?myNumber 等于內(nèi)存地址 0012CCGWH80,所以將它賦值給 newVar 就等于將0012CCGWH80 賦值給 newVar

現(xiàn)在,如果我這樣做會(huì)發(fā)生什么:

myNumber = myNumber + 1

myNumber的值肯定是 24。但是newVar的值是否也為 24 呢?,因?yàn)樗鼈冎赶蛳嗤膬?nèi)存地址?

答案是否定的。由于JS中的原始數(shù)據(jù)類型是不可變的,當(dāng) myNumber + 1 解析為24時(shí),JS 將在內(nèi)存中分配一個(gè)新地址,將24作為其值存儲(chǔ),myNumber將指向新地址。

這是另一個(gè)例子:

let myString = "abc"
myString = myString + "d"

雖然一個(gè)初級(jí) JS 程序員可能會(huì)說,字母d只是簡單在原來存放adbc內(nèi)存地址上的值,從技術(shù)上講,這是錯(cuò)的。當(dāng) abcd 拼接時(shí),因?yàn)樽址彩荍S中的基本數(shù)據(jù)類型,不可變的,所以需要分配一個(gè)新的內(nèi)存地址,abcd 存儲(chǔ)在這個(gè)新的內(nèi)存地址中,myString 指向這個(gè)新的內(nèi)存地址。

下一步是了解原始數(shù)據(jù)類型的內(nèi)存分配位置。

JavaScript 內(nèi)存模型:調(diào)用堆棧和堆

JS 內(nèi)存模型可以理解為有兩個(gè)不同的區(qū)域:調(diào)用堆棧(call stack)堆(heap)。

調(diào)用堆棧是存放原始數(shù)據(jù)類型的地方(除了函數(shù)調(diào)用之外)。上一節(jié)中聲明變量后調(diào)用堆棧的粗略表示如下。

在上圖中,我抽象出了內(nèi)存地址以顯示每個(gè)變量的值。 但是,不要忘記實(shí)際上變量指向內(nèi)存地址,然后保存一個(gè)值。 這將是理解 let vs. const 一節(jié)的關(guān)鍵。

是存儲(chǔ)引用類型的地方。跟調(diào)用堆棧主要的區(qū)別在于,堆可以存儲(chǔ)無序的數(shù)據(jù),這些數(shù)據(jù)可以動(dòng)態(tài)地增長,非常適合數(shù)組和對(duì)象。

JS 引用類型的變量聲明和賦值

讓我們從一個(gè)簡單的例子開始。下面,我們聲明一個(gè)名為myArray的變量,并用一個(gè)空數(shù)組初始化它。

let myArray = []

當(dāng)你聲明變量“myArray”并為其指定非原始數(shù)據(jù)類型(如“[]”)時(shí),以下是在內(nèi)存中發(fā)生的情況:

為變量創(chuàng)建唯一標(biāo)識(shí)符(“myArray”)

在內(nèi)存中分配一個(gè)地址(將在運(yùn)行時(shí)分配)

存儲(chǔ)在堆上分配的內(nèi)存地址的值(將在運(yùn)行時(shí)分配)

堆上的內(nèi)存地址存儲(chǔ)分配的值(空數(shù)組[])

從這里,我們可以 push, pop,或?qū)?shù)組做任何我們想做的。

myArray.push("first")
myArray.push("second")
myArray.push("third")
myArray.push("fourth")
myArray.pop()

let vs const

一般來說,我們應(yīng)該盡可能多地使用const,只有當(dāng)我們知道某個(gè)變量將發(fā)生改變時(shí)才使用let。

讓我們明確一下我們所說的“改變”是什么意思。

let sum = 0
sum = 1 + 2 + 3 + 4 + 5
let numbers = []
numbers.push(1)
numbers.push(2)
numbers.push(3)
numbers.push(4)
numbers.push(5)

這個(gè)程序員使用let正確地聲明了sum,因?yàn)樗麄冎乐禃?huì)改變。但是,這個(gè)程序員使用let錯(cuò)誤地聲明了數(shù)組 numbers ,因?yàn)樗麑褨|西推入數(shù)組理解為改變數(shù)組的值。

解釋“改變”的正確方法是更改內(nèi)存地址。let 允許你更改內(nèi)存地址。const 不允許你更改內(nèi)存地址。

const importantID = 489
importantID = 100 // 類型錯(cuò)誤:賦值給常量變量

讓我們想象一下這里發(fā)生了什么。

當(dāng)聲明importantID時(shí),分配了一個(gè)內(nèi)存地址,并存儲(chǔ)489的值。記住,將變量importantID看作等于內(nèi)存地址。

當(dāng)將100分配給importantID時(shí),因?yàn)?b>100是一個(gè)原始數(shù)據(jù)類型,所以會(huì)分配一個(gè)新的內(nèi)存地址,并將100的值存儲(chǔ)這里。

然后 JS 嘗試將新的內(nèi)存地址分配給 importantID,這就是拋出錯(cuò)誤的地方,這也是我們想要的行為,因?yàn)槲覀儾幌敫淖冞@個(gè) importantID的值。

當(dāng)你將100分配給importantID時(shí),實(shí)際上是在嘗試分配存儲(chǔ)100的新內(nèi)存地址,這是不允許的,因?yàn)?b>importantID是用const聲明的。

如上所述,假設(shè)的初級(jí)JS程序員使用let錯(cuò)誤地聲明了他們的數(shù)組。相反,他們應(yīng)該用const聲明它。這在一開始看起來可能令人困惑,我承認(rèn)這一點(diǎn)也不直觀。

初學(xué)者會(huì)認(rèn)為數(shù)組只有在我們可以改變的情況下才有用,const 使數(shù)組不可變,那么為什么要使用它呢? 請(qǐng)記住:“改變”是指改變內(nèi)存地址。讓我們深入探討一下為什么使用const聲明數(shù)組是完全可以的。

const myArray = []

在聲明 myArray 時(shí),將在調(diào)用堆棧上分配內(nèi)存地址,該值是在堆上分配的內(nèi)存地址。堆上存儲(chǔ)的值是實(shí)際的空數(shù)組。想象一下,它是這樣的:

如果我們這么做:

myArray.push(1)
myArray.push(2)
myArray.push(3)
myArray.push(4)
myArray.push(5)

執(zhí)行 push 操作實(shí)際是將數(shù)字放入堆中存在的數(shù)組。而 myArray 的內(nèi)存地址沒有改變。這就是為什么雖然使用const聲明了myArray,但沒有拋出任何錯(cuò)誤。

myArray 仍然等于 0458AFCZX91,它的值是另一個(gè)內(nèi)存地址22VVCX011,它在堆上有一個(gè)數(shù)組的值。

如果我們這樣做,就會(huì)拋出一個(gè)錯(cuò)誤:

myArray = 3

由于 3 是一個(gè)原始數(shù)據(jù)類型,因此生成一個(gè)新的調(diào)用堆棧上的內(nèi)存地址,其值為 3,然后我們將嘗試將新的內(nèi)存地址分配給 myArray,由于myArray是用const聲明的,所以這是不允許的。

另一個(gè)會(huì)拋出錯(cuò)誤的例子:

myArray = ["a"]

由于[a]是一個(gè)新的引用類型的數(shù)組,因此將分配調(diào)用堆棧上的一個(gè)新內(nèi)存地址,并存儲(chǔ)上的一個(gè)內(nèi)存地址的值,其它值為 [a]。然后,我們嘗試將調(diào)用堆棧內(nèi)存地址分配給 myArray,這會(huì)拋出一個(gè)錯(cuò)誤。

對(duì)于使用const聲明的對(duì)象(如數(shù)組),由于對(duì)象是引用類型,因此可以添加鍵,更新值等等。

const myObj = {}
myObj["newKey"] = "someValue" // 這不會(huì)拋出錯(cuò)誤

為什么這些知識(shí)對(duì)我們有用呢

JavaScript 是世界上排名第一的編程語言(根據(jù)GitHub和Stack Overflow的年度開發(fā)人員調(diào)查)。 掌握并成為“JS忍者”是我們所有人都渴望成為的人。

任何質(zhì)量好的的 JS 課程或書籍都提倡使用let, const 來代替 var,但他們并不一定說出原因。 對(duì)于初學(xué)者來說,為什么某些 const 變量在“改變”其值時(shí)會(huì)拋出錯(cuò)誤而其他 const變量卻沒有。 對(duì)我來說這是有道理的,為什么這些程序員默認(rèn)使用let到處避免麻煩。

但是,不建議這樣做。谷歌擁有世界上最好的一些程序員,在他們的JavaScript風(fēng)格指南中說,使用 constlet 聲明所有本地變量。默認(rèn)情況下使用 const,除非需要重新分配變量,不使用 var 關(guān)鍵字(原文)。

雖然他們沒有明確說明原因,但據(jù)我所知,有幾個(gè)原因

先發(fā)制人地限制未來的 bug。

使用 const 聲明的變量必須在聲明時(shí)初始化,這迫使程序員經(jīng)常在范圍方面更仔細(xì)地放置它們。這最終會(huì)導(dǎo)致更好的內(nèi)存管理和性能。

要通過代碼與任何可能遇到它的人交流,哪些變量是不可變的(就JS而言),哪些變量可以重新分配。

希望上面的解釋能幫助你開始明白為什么或者什么時(shí)候應(yīng)該在代碼中使用 letconst 。

代碼部署后可能存在的BUG沒法實(shí)時(shí)知道,事后為了解決這些BUG,花了大量的時(shí)間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個(gè)好用的BUG監(jiān)控工具 Fundebug。

你的點(diǎn)贊是我持續(xù)分享好東西的動(dòng)力,歡迎點(diǎn)贊!

交流

干貨系列文章匯總?cè)缦?,覺得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。

https://github.com/qq44924588...

我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!

關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/103530.html

相關(guān)文章

  • JavaScript 如何工作JavaScript 共享傳遞和按值傳遞

    摘要:它對(duì)數(shù)組和對(duì)象使用按值傳遞,但這是在的共享傳參或拷貝的引用中使用的按值傳參。例如在這里,變量和值在執(zhí)行期間存儲(chǔ)在堆棧中。返回值這是可選的,函數(shù)可以返回值,也可以不返回值。變量被推入堆棧,從而在執(zhí)行時(shí)成為的副本。 這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 22 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過了前面的章節(jié),可...

    keithyau 評(píng)論0 收藏0
  • JavaScript 如何工作JavaScript 共享傳遞和按值傳遞

    摘要:它對(duì)數(shù)組和對(duì)象使用按值傳遞,但這是在的共享傳參或拷貝的引用中使用的按值傳參。例如在這里,變量和值在執(zhí)行期間存儲(chǔ)在堆棧中。返回值這是可選的,函數(shù)可以返回值,也可以不返回值。變量被推入堆棧,從而在執(zhí)行時(shí)成為的副本。 這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 22 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過了前面的章節(jié),可...

    陳偉 評(píng)論0 收藏0
  • JavaScript工作原理(六):WebAssembly比較分析和特定情況下最好在JavaScri

    摘要:我們將拆分來分析它的工作原理,更重要的是,它在性能方面如何提升加載時(shí)間,執(zhí)行速度,垃圾回收,內(nèi)存使用率,平臺(tái)訪問,調(diào)試,多線程和可移植性。目前,是圍繞和用例設(shè)計(jì)的。多線程在單個(gè)線程上運(yùn)行。目前不支持多線程。被設(shè)計(jì)為安全和便攜。 我們將拆分WebAssembly來分析它的工作原理,更重要的是,它在性能方面如何提升JavaScript:加載時(shí)間,執(zhí)行速度,垃圾回收,內(nèi)存使用率,平臺(tái)API訪...

    novo 評(píng)論0 收藏0
  • JavaScript 如何工作系列文章已更新到22篇

    摘要:為了方便大家共同學(xué)習(xí),整理了之前博客系列的文章,目前已整理是如何工作這個(gè)系列,可以請(qǐng)猛戳博客查看。以下列出該系列目錄,歡迎點(diǎn)個(gè)星星,我將更友動(dòng)力整理理優(yōu)質(zhì)的文章,一起學(xué)習(xí)。 為了方便大家共同學(xué)習(xí),整理了之前博客系列的文章,目前已整理 JavaScript 是如何工作這個(gè)系列,可以請(qǐng)猛戳GitHub博客查看。 以下列出該系列目錄,歡迎點(diǎn)個(gè)星星,我將更友動(dòng)力整理理優(yōu)質(zhì)的文章,一起學(xué)習(xí)。 J...

    lx1036 評(píng)論0 收藏0
  • 【譯】JavaScript面試問題:事件委托和this

    摘要:主題來自于的典型面試問題列表。有多種方法來處理事件委托。這種方法的缺點(diǎn)是父容器的偵聽器可能需要檢查事件來選擇正確的操作,而元素本身不會(huì)是一個(gè)監(jiān)聽器。 showImg(http://fw008950-flywheel.netdna-ssl.com/wp-content/uploads/2014/11/Get-Hired-Fast-How-to-Job-Search-Classifieds...

    浠ラ箍 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<