js var是什么類型_JS變量的執行環境和生命周期

14afa78d6b08d5cdefe82ceae639e550.png

溫故而知新,這些JS基礎知識你都知道嗎?

今天和大家分享的是 JavaScript 中有關變量的知識,希望這篇文章能讓你對JS中的變量有新的認識.

目錄:

  • 變量的執行環境(執行上下文)
  • 執行上下文的生命周期
  • 創建變量對象
  • 變量的數據存儲
  • 變量的內存空間
  • 變量的垃圾回收
  • let/const/var的區別

執行環境(執行上下文)

javascript的運行環境主要包括以下三種:

  1. 全局環境:代碼運行起來后會首先進入全局環境.
  2. 函數環境:當函數被調用時,會進入當前函數中執行代碼.
  3. eval環境:不建議使用,這里不做介紹.

js運行環境也叫做執行上下文,因此在一個JavaScript程序中,必定會出現多個執行上下文.

JS引擎會以棧(遵循后進先出的數據存儲方式)的方式來處理執行上下文,也就是我們通常所說的函數調用棧。棧底永遠是全局上下文,棧頂則是當前正在執行的上下文. 處于棧頂的執行上下文執行完畢后,會自動出棧.

看個例子可能會更形象些:

function declare() {var a = 1;function update() {a = 2;}update();
}
declare();

下面是上方用例中的執行上下文對應的進出棧流程示意圖:

51d1540121fd8917a0042bc2e4a56f7d.png

假如上方的 declare 函數處于全局環境中,那么代碼運行時會經歷以下幾步:

  1. 首先第一步就是全局上下文入棧.
  2. 全局上下文入棧后,遇到的第一個可執行代碼就是 declare() 函數的調用,此函數一旦調用,就會創建自己的執行上下文,此時declare EC入棧.
  3. 在新開辟的declare EC執行上下文中,執行內部的可執行代碼,直到遇到 update() 函數調用時,又會創建一個新的執行上下文,此時update EC入棧.
  4. 當update EC中的可執行代碼執行完畢之后,發現不再有其他執行上下文生成的情況,此上下文會自動從棧中彈出.
  5. update EC執行上下文彈出后,會繼續執行 declare EC執行上下文中的可執行代碼,直到順利執行完畢,且沒有遇到其他執行上下文,則自動從棧中彈出.
  6. 最后執行棧中只剩下全局上下文,若瀏覽器不關閉,全局上下文會一直存在,直到瀏覽器窗口關閉,全局上下文才會最終出棧.

執行上下文的生命周期

說完執行上下文的入棧、出棧情況,下面說說執行上下文的生命周期.

當一個函數調用時,一個新的執行上下文就會被創建,一個執行上下文的生命周期可分為兩個階段:

  1. 創建階段 --- 此階段執行上下文會分別創建變量對象、確認作用域鏈、以及確定this指向.
  2. 執行階段 --- 執行代碼,這個時候會完成變量賦值、函數引用、以及執行其他可執行代碼等工作.

畫個圖看起來會更直觀:

6b2a64ede033a925bd681a8f312a22e8.png

這篇文章接下來主要介紹變量的生命周期,所以我們主要針對執行上下文中 創建變量對象、內存空間、變量賦值階段 展開講解。

創建變量對象

JS中聲明的所有變量都保存在變量對象中, 變量對象的創建依次經歷以下步驟:

1. 首先獲得函數的參數變量及其值.

2. 依次獲取當前上下文中所有的函數聲明. 在變量對象中會以函數名建立一個屬性,屬性值指向該函數所在的內存地址.

3. 依次獲取當前上下文中的變量聲明,每找到一個變量聲明,就在變量對象中以變量名建立一個屬性。 如果是var聲明,則屬性值會初始化為undefined.

變量的數據存儲

變量對象創建完成后,接下來就是對數據的存儲,基礎數據類型往往會保存在棧內存中(特殊情況除外),而引用數據類型的值是保存在堆內存中的對象,在js語言中,不允許直接訪問堆內存空間中的數據. 當我們操作對象時實際上是在操作對象的引用,而不是實際的對象. 因此,引用數據類型都是按引用訪問的,這里的引用可以理解為保存在變量對象中的一個地址,該地址與堆內存中的對象相關聯.

下邊通過一個列子,來看下變量對象的存儲:

function fun(){var a = 1;var b = 'hello world';var c = {x: 100};var d = {y: [1,2]};
}

當fun()函數調用時,會創建一個執行上下文,在當前上下文中創建變量對象,變量對象存放格式如下:

d759e4a49df44cc2e498eb648467abb4.png

如果是基本數據類型,在棧中存儲數據本身; 如果是引用數據類型,在棧中存儲的是堆中對象的引用;

變量的內存空間

說完變量對象的創建與存儲之后,接下來再說說變量的內存空間的使用過程. 內存空間的使用同樣也具有自己的生命周期,包含:

  1. 分配內存階段
  2. 使用分配到的內存
  3. 不需要時釋放內存

再來看個例子:

var a = 20; // 分配內存
console.log(a + 1); // 使用內存
a = null; // 釋放內存

上邊的三行代碼分別對應著分配內存、使用分配到的內存、以及釋放內存三個過程。其中,分配和使用應該很好理解,最終要的是釋放的過程,涉及到垃圾回收機制的實現原理。

變量的垃圾回收

Javascript中具有自動垃圾收集機制,也就是說,執行環境會負責管理代碼執行過程中使用的內存。所以,在日常開發中,開發人員很少再關心內存使用的問題.

垃圾回收機制的原理就是:找出那些不再繼續使用的變量,垃圾收集器會按照固定的時間間隔,周期性的釋放其占用的內存.

最常用的垃圾收集方式是標記清除算法. 主要依靠 "引用" 的概念,當一塊內存空間中的數據能夠被訪問時,垃圾回收器就會認為 "該數據能夠被獲得",不能夠被獲得的數據,就會被打上標記,并回收內存空間,這種方式叫做 標記 --- 清除算法.

注: 在局部作用域中,當函數執行完畢后,垃圾收集器會很容易做出判斷并做局部變量做回收操作。但在全局作用域中,變量什么時候需要自動釋放內存空間則很難判斷,所以,我們在做開發時,應盡量避免全局變量的使用。如果使用了全局變量,建議通過 a = null 這樣的方式釋放引用,以確保能夠及時的回收內存空間.

介紹完了執行環境、變量對象的創建、內存、垃圾回收后。我們再來看一個最常見的問題:let/const/var 關鍵字聲明變量的方式,來熟悉下變量的生命周期以及它們之間存在的區別.

----------------- 我是分割線 ----------------

let/const/var的區別

關于var、let、const的各自特性,想必大家都已經很清楚了,這里簡單羅列:

2618b54c7c8da977fb8fd3e388162c09.png

使用以上三個關鍵詞定義的變量,之所以會有不同的使用特性,這跟他們的生命周期有直接的關系。 JS引擎下,變量的生命周期包含四個階段:

  • - 聲明階段
  • - 初始化階段
  • - 賦值階段
  • - 釋放階段

下邊來分別分析下它們生命周期中存在的區別:

  1. var 聲明變量的生命周期

0c643ea563bbbdf5824549f2e90557f3.png

當使用var聲明一個變量時:

// 第一個特性
function fun() {// 變量提升 -- 不存在暫時性死區console.log(a); // undefinedvar a = 1;
}// 第二個特性 --- 不支持塊級作用域
console.log(a); // undefined
{var a = 1;
}
console.log(a); // 1

以函數作用域為例,在函數作用域中遇到 var a = 1 這段代碼,編譯器會首先查找當前作用域下是否已經聲明過該變量,若已經存在,則直接忽略這次聲明;若不存在,則在當前作用域中聲明一個名字為 a 的變量,并進行初始化操作(變量 a 的值初始化為 undefined),這也是為什么使用 var 可以進行重復聲明的原因. 這里的聲明和初始化均被提升至作用域的最頂端.

當函數調用執行時,JS引擎會在當前的函數作用域為該變量進行賦值操作,在 var a = 1 這條語句之前的任何位置訪問變量 a,它的值將會是 undefined. 因為初始化操作也被進行了提升.

當代碼執行至 var a = 1 時,引擎也會從當前作用域下查找是否存在變量 a, 若存在,直接進行賦值;若不存在會強制在當前作用域聲明一個變量 a, 并進行賦值操作.

注: 不要隨意在代碼塊中使用var聲明變量,因為它會直接掛到全局變量window對象上,污染全局環境,且不能及時的進行垃圾回收釋放內存.

----------------- 我是分割線 ----------------

2. let 聲明變量的生命周期

cbbc2c26f10835ee78ce27a3e3a59eb0.png

使用let進行變量聲明:

// 第一個特性 --- 塊級作用域
{let a = 1;
}
console.log(a); // a is not defined// 第二個特性 --- 暫時性死區
console.log(a); // a is not defined
let a = 1;// 第三個特性 --- 不可重復聲明
let a;
let a = 1; // Uncaught SyntaxError: Identifier 'a' has already been declared

let 的生命周期與 var 的主要區別在于,聲明和初始化階段沒有同時進行提升,只有聲明階段被提升至當前作用域的最上方,所以在聲明和初始化階段之間就出現了暫時性死區現象,此階段不可訪問該變量,否則會拋出異常.

let 不可重復聲明,遇到let聲明的變量時,編譯器同樣會先查找當前作用域下是否已經聲明過該變量,若已經存在,引擎就會拋出異常(Uncaught SyntaxError: Identifier 'a' has already been declared);若不存在,則在當前作用域中聲明一個名字為 a 的變量,并把聲明操作提升至作用域最上方.

最重要的是 let 具備了塊級作用域,它很好的規避了 var 身上的缺點,在代碼塊內聲明變量,避免污染全局變量.

----------------- 我是分割線 ----------------

3. const 聲明變量的生命周期

0cf44b11107e5c38422bec762749cbad.png

使用const聲明變量:

// 第一個特性 --- 一旦聲明不可修改
const a = 1;
a = 2; // Uncaught TypeError: Assignment to constant variable.// 第二個特性 --- 存在暫時性死區
console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization (初始化前無法訪問a)
const a = 1;

let 最大的區別是 const 是用來定義常量的,它創建一個值得只讀引用,一旦定義不可修改. const 也存在暫時性死區, 如果我們在聲明之前訪問該變量的值,則會拋出異常(初始化前無法訪問該變量),這也很好的證明了,const 的生命周期同樣存在聲明提升,并且它的初始化和賦值操作必須一起完成.

注: 使用 const 聲明變量時,實際上保證的并不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對于簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同于常量。但對于復合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(即總是指向另一個固定的地址),至于它指向的數據結構是不是可變的,就完全不能控制了。

一個常量不能和它所在作用域內的其他變量或函數擁有相同的名稱. 更多const示例描述,可參考:

const?developer.mozilla.org
847dd7fd4f79eff83706c4a7a82b2850.png

不管是var、let、還是const聲明的變量,在變量使用完畢后,最終都會隨著執行上下文的出棧、瀏覽器的關閉、或者手動釋放內存的環節進行垃圾回收. 由于JS中自動垃圾回收機制的存在,使我們往往在開發時忽略了內存使用的問題,但這個是所有變量都要經歷的過程.

以上就是今天的所有分享啦~ 感謝您認真讀完,共勉!

參考文獻:

《Javascript高級程序設計》

《Javascript核心技術開發解密》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/271528.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/271528.shtml
英文地址,請注明出處:http://en.pswp.cn/news/271528.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡中不能顯示全部計算機,win10家庭版局域網中計算機設備無法完全顯示的解決方法...

許多用戶都喜歡通過局域網來共享一些文件等,打開局域網就可以看到所有共享的計算機,然而有不少win10家庭版用戶卻發現局域網中只能看到幾臺計算機設備,無法完全顯示,該怎么辦呢,現在為大家講解一下win10家庭版局域網中…

java.lang.NoClassDefFoundError:org/apache/commons/io/Charsets (jsoup配合htmlunit 爬取異步加載的網頁遇到的)

最近用jsoup配合htmlunit 爬取異步加載的網頁運行代碼的時候,報錯java.lang.NoClassDefFoundError:org/apache/commons/io/Charsets 報錯截圖如下 解決措施: 1:common-fileupload 1.3.1的版本依賴的commons-io 2.2,而htmlunit的jar依賴的是common-io 2.4 htmlunit…

echarts 3d地球 背面光線太暗_新技術:多波長光源,同時3D打印多種光敏樹脂材料...

如今,光固化3D打印技術已經被廣泛的采用,在齒科、首飾、手辦等領域,然而如上圖一樣的常規光固化3D打印機,一次仍然只能打印一種材料。 △FDM技術類型的3D打印機可以通過增加噴頭數量來實現多色或者多種材料同時打印,圖…

2016-6-28 工作總結

今天是軟件工程課設開始的第一天。經過一早上聽老師的課程說明與用戶反饋的講解,我可以看得出老師對于這次課程設計的質量有著很高的期待與嚴格的要求,不再允許有渾水摸魚的現象發生,我想,從某種程度上來講,是一種好事…

計算機系統基礎:計算機性能評價知識筆記

1、計算機性能常用的性能評測方法 1.1 時鐘頻率 計算機的時鐘頻率可以反映出機器的運行速度。一般主頻越高,速度越快。 1.2 指令執行速度 加法指令執行速度是衡量計算機性能指標的重要指標之一。 1.3 等效指令速度法 隨著計算機指令系統發展,種類越來越多…

astc貼圖格式是什么意思_c4d配合AEe3d導入c4d模型貼圖及插件安裝所有流程

所有使用的軟件及插件,分享給大家,需要軟件或者插件的可以留言我,免費分享給大家,其實也可以網上下載到,就是有的版本和相應需要的插件不兼容和支持,。不少小伙伴用c4d做模型,做好后到底怎么玩&…

html5做文字顏色漸變代碼,神奇!js+CSS+DIV實現文字顏色漸變效果_javascript技巧

本文實例為大家分享了DIVCSSJS實現的文字顏色漸變效果,供大家參考,具體內容如下下面是 CSS 部分代碼:body{ font:12px/1.5 Microsoft Yahei;}h3{ padding:10px; margin:0; background-color:#999; color:#fff; font:16px/1.5 Microsoft Yahei…

前大燈是近光燈還是遠光燈_汽修案例:長安福特翼博前大燈間歇自動點亮

點擊↑汽修案例關注置頂,獲得正時大全一輛行駛里程約2300km的2017年長安福特翼博。客戶反映:該車在行駛過程中前大燈間歇出現自動點亮的故障現象。故障現象出現時大燈點亮與否不受大燈開關控制,如圖1所示。故障診斷:車輛來店報修時…

commons-httpclient 和 httpclient 區別

commons-httpclient 和 httpclient 區別 項目里的pom中&#xff0c;里面有這么兩個包依賴。 <dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version> </depend…

計算機基礎:多媒體基礎知識筆記

1、媒體的定義 媒體包括兩面&#xff1a; 1、物理載體&#xff1a;比如磁盤、光盤、磁帶以及相關的播放設備。 2、信息載體&#xff1a;也就是信息的表現形式&#xff0c;比如文字、聲音、圖像、動畫、視頻等。CCITT定義的存儲媒體和表示媒體。 2、媒體的分類 1、感覺媒體&…

gnuradio上怎么使用python文件_使用Python從PDF文件中提取數據

前言數據是數據科學中任何分析的關鍵&#xff0c;大多數分析中最常用的數據集類型是存儲在逗號分隔值(csv)表中的干凈數據。然而&#xff0c;由于可移植文檔格式(pdf)文件是最常用的文件格式之一&#xff0c;因此每個數據科學家都應該了解如何從pdf文件中提取數據&#xff0c;并…

Attach Volume 操作(Part I) - 每天5分鐘玩轉 OpenStack(53)

上一節我們創建了 volume&#xff0c;本節討論如何將 volume attach 到 Instance&#xff0c;今天是第一部分。 Volume 的最主要用途是作為虛擬硬盤提供給 instance 使用。Volume 是通過 Attach 操作掛載到 instance 上的。本節我們就來詳細討論 Cinder 是如何實現 Attach 的。…

計算機網絡技術課程代碼02141模擬試題,02141計算機網絡技術201510真題及答案

2015年10月高等教育自學考試全國統一命題考試計算機網絡技術試卷(課程代碼02141)本試卷共4頁。滿分l00分&#xff0c;考試時間l50分鐘。考生答題注意事項&#xff1a;1&#xff0e;本卷所有試題必須在答題卡上作答。答在試卷上無效&#xff0c;試卷空白處和背面均可作草稿紙。2…

python如何確定拐點_多年股市老鳥買賣操作經驗——如何在波段操作確定買入點!經典...

多年股市老鳥買賣操作經驗——如何在波段操作確定買入點&#xff01;經典&#xff01;股市諺語&#xff1a;“長線是金,短線是銀,波段操作是鉆石。”這從一個側面反映了波段操作的重要性。波段操作就是在股價趨勢變化的早期階段辨識買賣機會&#xff0c;在波動的階段性底部(谷底…

c#geckofx文件流下載

備注&#xff1a;內容僅提供參考。 ⒈添加引用&#xff1a;using Gecko; ⒉然后根據自己的情況在某個方法內添加事件&#xff1a; LauncherDialog.Download new EventHandler<LauncherDialogEvent>(OnDownloadFile); ⒊再聲明方法&#xff1a; private void OnDownloadF…

獲取后端接口請求中的參數(@PathVariable,@RequestParam,@RequestBody區別,使用postman請求

獲取參數 SpringBoot提供的獲取參數注解包括&#xff1a;PathVariable&#xff0c;RequestParam&#xff0c;RequestBody,三者的區別如下表&#xff1a; 一:后端接口什么都不加 postman請求后端接口 二:后端接口加RequestParam POST請求RequestParam&#xff1a; ① 用來處理…

spark shell 刪除失效_Spark任務提交源碼解析

1. 前言反反復復搗鼓了很久&#xff0c;終于開始學習Spark的源碼了&#xff0c;果不其然&#xff0c;那真的很有趣。這里我打算一本正經的胡說八道來講一下Spark作業的提交過程。基礎mac系統基礎環境如下&#xff1a;JDK 1.8IDEA 2019.3源碼Spark 2.3.3Scala 2.11.8提交腳本# 事…

硬件基礎:理解串口通信以及232,485,422常見問題

這里并不對串口的編程作講解&#xff0c;主要是從應用的角度去講一講。因為更多的時候&#xff0c;都是產品做好了&#xff0c;比如觸摸屏需要和控制器&#xff0c;PLC通信。理想的情況下&#xff0c;一般只要一上電&#xff0c;不需要太多的操作和配置&#xff0c;就可以通信上…

decimal轉為string sql_SQL注入詳解|OWASP Top 10安全風險實踐(二)

本文為一些列連載文章之一&#xff0c;不定期更新&#xff0c;計劃目錄如下&#xff1a;OWASP介紹SQL注入命令注入XML外部實體注入XPATH注入反射式、DOM及存儲XSS失效的身份認證和會話管理不安全的直接對象引用安全配置錯誤敏感信息泄露功能級訪問控制缺失跨站請求偽造服務端請…

各類排序算法實現(親測)

排序算法通常分為外部排序和內部排序&#xff0c;通常所說的八類排序屬于內部排序&#xff1b; 外部排序在此不說明&#xff0c;主要給出八類排序的簡單思想和實現&#xff1a; 1.插入排序 1.1 直接插入排序&#xff1a; 每次將一個新數&#xff0c;插入到已經排列好的有序…