JavaScript 執(zhí)行

JavaScript 執(zhí)行

一段 JavaScript 經(jīng)過編譯會生成兩部分:執(zhí)行上下文,可執(zhí)行代碼。
在執(zhí)行上下文中存在一個變量環(huán)境對象(Viriable Environment),保存了變量提升的內(nèi)容。

簡單的變量環(huán)境對象

VariableEnvironment:
     myname -> undefined, 
     showName ->function : {console.log(myname)

JavaScript 代碼先編譯在執(zhí)行

showName()
console.log(myname)
var myname = 'hello'
function showName() {
    console.log('函數(shù)showName被執(zhí)行');
}
  1. JS 引擎在環(huán)境對象中創(chuàng)建一個名為myname屬性,并用 undefined 對其初始;
  2. JS 引擎發(fā)現(xiàn)同 function 定義的函數(shù),把函數(shù)定義存儲在堆(HEAP)中,并在環(huán)境對象中創(chuàng)建一個 showName 的屬性,然后將地址指向堆中的環(huán)境位置;
  3. JS 引擎會把聲明外的代碼編譯為字節(jié)碼

調(diào)用棧 call statck

調(diào)用棧是用來管理函數(shù)調(diào)用關(guān)系的一種數(shù)據(jù)結(jié)構(gòu)
把這種用來管理執(zhí)行上下文的棧成為執(zhí)行上下文棧,又稱調(diào)用棧
console.track() 查看調(diào)用棧

let 和 const

作用域 scope
作用域是指在程序中定義變量的區(qū)域,該位置決定了變量的生命周期。通俗地理解,作用域就是變量與函數(shù)的可訪問范圍,即作用域控制著變量和函數(shù)的可見性和生命周期。

  • 全局作用域中的對象在代碼中的任何地方都能訪問,其生命周期伴隨著頁面的生命周期
  • 函數(shù)作用域就是在函數(shù)內(nèi)部定義的變量或者函數(shù),并且定義的變量或者函數(shù)只能在函數(shù)內(nèi)部被訪問。函數(shù)執(zhí)行結(jié)束之后,函數(shù)內(nèi)部定義的變量會被銷毀
    代碼塊內(nèi)部定義的變量外部是訪問不到的,代碼塊中的代碼執(zhí)行完成,代碼塊中定義的變量就會銷毀。

S6 之前是不支持塊級作用域的,因?yàn)楫?dāng)初設(shè)計(jì)這門語言的時候,并沒有想到 JavaScript 會火起來,所以只是按照最簡單的方式來設(shè)計(jì)。沒有了塊級作用域,再把作用域內(nèi)部的變量統(tǒng)一提升無疑是最快速、最簡單的設(shè)計(jì),不過這也直接導(dǎo)致了函數(shù)中的變量無論是在哪里聲明的,在編譯階段都會被提取到執(zhí)行上下文的變量環(huán)境中,所以這些變量在整個函數(shù)體內(nèi)部的任何地方都是能被訪問的,這也就是 JavaScript 中的變量提升。

ES6 是如何做到既要支持變量提升的特性,又要支持塊級作用域的呢?”

  • 第一步是編譯并創(chuàng)建執(zhí)行上下文,下面是我畫出來的執(zhí)行上下文示意圖,你可以參考下:
  • 函數(shù)內(nèi)部通過 var 聲明的變量,在編譯階段全都被存放到變量環(huán)境里面了。
  • 通過 let 聲明的變量,在編譯階段會被存放到詞法環(huán)境(Lexical Environment)中
  • 在函數(shù)的作用域內(nèi)部,通過 let 聲明的變量并沒有被存放到詞法環(huán)境中。

作用域鏈

每個執(zhí)行上下文的變量環(huán)境中,都包含一個外部引用,
用來指向外部的執(zhí)行上下文,我們把這個外部引用成為outer.

詞法作用域
詞法作用域是指作用域是有代碼中函數(shù)聲明的
法作用域是代碼階段就決定好的,和函數(shù)是怎么調(diào)用的沒有關(guān)系
詞法作用域
詞法作用域是指作用域是由代碼中函數(shù)聲明的位置來決定的,所以詞法作用域是靜態(tài)作用域。詞法作用域是代碼階段就確定好的,和函數(shù)執(zhí)行無關(guān)。

閉包


function foo() {
    var myName = "li"
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName:function(){
            console.log(test1)
            return myName
        },
        setName:function(newName){
            myName = newName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName("liyunfei")
bar.getName()
console.log(bar.getName())

當(dāng)執(zhí)行到foo函數(shù)時的調(diào)用棧情況

foo函數(shù)執(zhí)行上下文 =》變量環(huán)境, 詞法環(huán)境

全局執(zhí)行上下文 =》變量環(huán)境, 詞法環(huán)境

閉包是怎么回收的

this

執(zhí)行上下文:
變量環(huán)境、詞法環(huán)境、outer、this;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容