国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

什么是作用域和執(zhí)行上下文

felix0913 / 2889人閱讀

摘要:等這個新的作用域生命周期完成后,作用域鏈又會恢復(fù)到之前的狀況,然后執(zhí)行上下文保存的作用域也會恢復(fù)成之前的。

說到 Javascript 中的作用域,通常一同出現(xiàn)的還有一個執(zhí)行上下文(execution context)的概念,以前我在網(wǎng)上搜索相關(guān)的內(nèi)容總是理不清這兩者的關(guān)系。似乎函數(shù),作用域,執(zhí)行上下文這三者天生就是糾纏在一起的。為了獲得一手的資料我翻看了 ES6 規(guī)范,把他們到底是什么梳理了一下:

作用域

首先我們來說下作用域,簡單來說作用域就是一個區(qū)域,包含了其中變量,常量,函數(shù)等等定義信息和賦值信息,以及這個區(qū)域內(nèi)代碼書寫的結(jié)構(gòu)信息。作用域可以嵌套。我們通常知道 js 中函數(shù)的定義可以產(chǎn)生作用域,下面我們用具體代碼來示例下:

全局作用域(global scope)里面定義了兩個變量,一個函數(shù)。walk 函數(shù)生成的作用域里面定義了一個變量,兩個函數(shù)。innerFunc 和 anotherInnerFunc 這兩個函數(shù)生成的作用域里面分別定義了一個變量。在規(guī)范中作用域更官方的叫法是詞法環(huán)境(Lexical Environments)。什么意思?就是作用域包含哪些內(nèi)容取決于你代碼怎么寫,你把定義 go 變量寫在了 walk 函數(shù)里面,那么 go 變量就屬于 walk 函數(shù)作用域。

作用域其實(shí)由兩部分組成:

記錄作用域內(nèi)變量信息(我們假設(shè)變量,常量,函數(shù)等統(tǒng)稱為變量)和代碼結(jié)構(gòu)信息的東西,稱之為 Environment Record。

一個引用 __outer__,這個引用指向當(dāng)前作用域的父作用域。拿上面代碼為例。innerFunc 的函數(shù)作用域有一個引用指向 walk 函數(shù)作用域,walk 函數(shù)作用域有一個引用指向全局作用域。全局作用域的 __outer__ 為 null。

變量查找(ResolveBinding):

規(guī)范中定義了查找一個變量的過程:先查看當(dāng)前作用域里面的 Environment Record 是否有此變量的信息,如果找到了,則返回當(dāng)前作用域內(nèi)的這個變量。如果沒有查找到,則順著 __outer__ 到父作用域里面的 Environment Record 查找,以此遞歸。所以我們通常所說的函數(shù)內(nèi)同名變量遮蔽全局變量就是這么回事。不過如果你在變量查找的時候指定某個作用域中的 Environment Record,那么也是可以的,譬如:window.name 【其實(shí) window 對象就是全局作用域的 Environment Record 對象,但是普通函數(shù)作用域的 Environment Record 對象是獲取不到的】。

生成作用域的語法:

函數(shù)聲明

function f() {
  var inner = "inner";
  console.log( inner );
}
f(); // inner;
console.log( inner ); // Uncaught ReferenceError: inner is not defined

catch 語句

try {
  throw new Error( "customized error" );
} catch( err ) {
  var iamnoterror = "not error";
  console.log( iamnoterror ); // not error
  console.log( err ); // Error: customized error
}
console.log( iamnoterror ); // not error
console.log( err ); // Uncaught ReferenceError: e is not defined

這里特別指出的是 catch 語句生成的作用域只會框住參數(shù)部分的變量(err),使其不能在外面訪問。對于 catch 語句體里面聲明的變量并不起作用。我們看規(guī)范里面怎么說:

For each element argName of the BoundNames of CatchParameter, do

Perform catchEnv.CreateMutableBinding(argName).

catchEvn 就是 catch 語句生成的作用域,但是這個作用域只保存參數(shù)列表中的變量(CreateMutableBinding(argName))。

語句塊

if ( true ) {
  let bv = "bv";
  const B_C = "BC";
  let blockFunc = function() {}
  function notBlockFunc() {}

  console.log( bv ); // bv
  console.log( B_C ); // BC
  console.log( notBlockFunc ); // function notBlockFunc() {}
  console.log( blockFunc ); // function () {}
  
}
console.log( bv ); // Uncaught ReferenceError: bv is not defined
console.log( B_C ); // Uncaught ReferenceError: B_C is not defined
console.log( notBlockFunc ); // function notBlockFunc() {}
console.log( blockFunc ); // ReferenceError: blockFunc is not defined

語句塊 {} 會生成一個新的作用域,但是這個作用域只綁定塊級變量,常量等,即 let,const 聲明的屬于塊級作用域,而 var 聲明的還是屬于塊級作用域的父作用域。

執(zhí)行上下文

接下來我們說下執(zhí)行上下文(execution context),執(zhí)行上下文是用于跟蹤代碼的運(yùn)行情況,其特征如下:

一段代碼塊對應(yīng)一個執(zhí)行上下文,被封裝成函數(shù)的代碼被視作一段代碼塊,或者“全局作用域”也被視作一段代碼塊。

當(dāng)程序運(yùn)行,進(jìn)入到某段代碼塊時,一個新的執(zhí)行上下文被創(chuàng)建,并被放入一個 stack 中。當(dāng)程序運(yùn)行到這段代碼塊結(jié)尾后,對應(yīng)的執(zhí)行上下文被彈出 stack。

當(dāng)程序在某段代碼塊中運(yùn)行到某個點(diǎn)需要轉(zhuǎn)到了另一個代碼塊時(調(diào)用了另一個函數(shù)),那么當(dāng)前的可執(zhí)行上下文的狀態(tài)會被置為掛起,然后生成一個新的可執(zhí)行上下文放入 stack 的頂部。

stack 最頂部的可執(zhí)行上下文被稱為 running execution context。當(dāng)頂部的可執(zhí)行上下文被彈出后,上一個掛起的可執(zhí)行上下文繼續(xù)執(zhí)行。

我們用代碼來示例下(從 outer 調(diào)用到 level1 調(diào)用,再逐層返回):

執(zhí)行上下文對象的內(nèi)部屬性:

[[code evaluation]]:當(dāng)前代碼塊執(zhí)行的狀態(tài):prerform,suspend,resume。

[[Function]]:如果當(dāng)前執(zhí)行上下文對應(yīng)的是一個函數(shù),那么這個屬性就保存的這個函數(shù)對象。如果對應(yīng)的是全局環(huán)境(可以是一個 script 或者 module),屬性值是 null。

[[Real]]:類似與沙箱的概念?(我還沒有看懂,不過不太影響此篇的內(nèi)容)。

如果程序執(zhí)行到某個點(diǎn)拋出異常了,那么我們可以用這個記錄執(zhí)行上下文的 stack 來追蹤到底哪里出錯了,可以看到整個調(diào)用棧,此時內(nèi)部屬性 [[Function]] 就起到作用了:

作用域和執(zhí)行上下文的關(guān)系

其實(shí)大家看下作用域和執(zhí)行上下文各自的職責(zé),你會發(fā)現(xiàn)他們幾乎是沒有啥交集的。那么為啥通常兩者會被同時提到呢?因?yàn)樵谝粋€函數(shù)被執(zhí)行時,創(chuàng)建的執(zhí)行上下文對象除了保存了些代碼執(zhí)行的信息,還會把當(dāng)前的作用域保存在執(zhí)行上下文中。所以它們的關(guān)系只是存儲關(guān)系。

再談變量查找(ResolveBinding):

結(jié)合作用域和執(zhí)行上下文,我們再來看下變量查找的過程。其實(shí)第一步不是到作用域里面找 Environment Record,而是先從當(dāng)前的執(zhí)行上下文中找保存的作用域(對象),然后再是通過作用域鏈向上查找變量。而且同一個執(zhí)行上下文保存的作用域(對象)是可變的,當(dāng)代碼在同一個執(zhí)行上下文中執(zhí)行的時候,如果碰到有必要生成一個新作用域的時候,這個新的作用域會被添加到作用域鏈的頭部,然后執(zhí)行上下文就保存的作用域?qū)ο缶透鲁蛇@個新的作用域。等這個新的作用域生命周期完成后,作用域鏈又會恢復(fù)到之前的狀況,然后執(zhí)行上下文保存的作用域也會恢復(fù)成之前的。示例:

this

稍微提下,我看到網(wǎng)上有把執(zhí)行上下文等同于 this 的文章,其實(shí) this 的值是通過當(dāng)前執(zhí)行上下文中保存的作用域(對象)來獲取到的,規(guī)范如下。

ResolveThisBinding ( )
The abstract operation ResolveThisBinding determines the binding of the keyword this using the LexicalEnvironment of the running execution context. ResolveThisBinding performs the following steps:

Let envRec be GetThisEnvironment( ).

Return envRec.GetThisBinding().

我接下來會要總結(jié)函數(shù)作為普通函數(shù)和作為構(gòu)造函數(shù)被調(diào)用時的區(qū)別,那個時候應(yīng)該會對 this 有更深入的解釋。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/83148.html

相關(guān)文章

  • 深入理解JavaScript作用域和作用域鏈

    前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...

    baiy 評論0 收藏0
  • 深入理解JavaScript作用域和作用域鏈

    前言 JavaScript中有一個被稱為作用域(Scope)的特性。雖然對于許多新手開發(fā)者來說,作用域的概念并不是很容易理解,本文我會盡我所能用最簡單的方式來解釋作用域和作用域鏈,希望大家有所收獲! 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客 作用域(Scope) 1.什么是作用域 作用域是在運(yùn)行時代碼中的某些特定部分中變量,函數(shù)和對象的可訪問性。換句話說,作用域決定了代碼區(qū)塊中變量和其他資源的可見...

    ytwman 評論0 收藏0
  • 關(guān)于javascript中的作用域和作用域鏈

    摘要:作用域的類別可以影響到變量的取值,分為詞法作用域靜態(tài)作用域和動態(tài)作用域。而,采用的就是詞法作用域,或者叫靜態(tài)作用域。 關(guān)于javascript中的作用域和作用域鏈 我GitHub上的菜鳥倉庫地址: 點(diǎn)擊跳轉(zhuǎn)查看其他相關(guān)文章 文章在我的博客上的地址: 點(diǎn)擊跳轉(zhuǎn) ? ? ? ? 前面的文章說到, 執(zhí)行上下文的創(chuàng)建階段,主要有三個內(nèi)容: ? ? ? ? 1、創(chuàng)建變量對象;2、初始化作用域...

    lcodecorex 評論0 收藏0
  • JavaScript深入之詞法作用域和動態(tài)作用

    摘要:作用域作用域是指程序源代碼中定義變量的區(qū)域。采用詞法作用域,也就是靜態(tài)作用域。而與詞法作用域相對的是動態(tài)作用域,函數(shù)的作用域是在函數(shù)調(diào)用的時候才決定的。前面我們已經(jīng)說了,采用的是靜態(tài)作用域,所以這個例子的結(jié)果是。 JavaScript深入系列的第二篇,JavaScript采用詞法作用域,什么語言采用了動態(tài)作用域?兩者的區(qū)別又是什么?還有一個略難的思考題,快來看看吧。 作用域 作用域是指...

    gclove 評論0 收藏0
  • JavaScript 作用域和作用域鏈學(xué)習(xí)

    摘要:作用域與作用域鏈每個函數(shù)都有自己的執(zhí)行環(huán)境。這是初步了解作用域,如想更深入了解作用域,請看下面鏈接作用域原理作用域鏈由一道題圖解的作用域或者看權(quán)威指南和高級程序設(shè)計(jì) 本文是我學(xué)習(xí)JavaScript作用域整理的筆記,如有不對,請多指出。 作用域 一個變量的作用域是程序源代碼中定義這個變量的區(qū)域。 而在ES5中只分為全局作用域和函數(shù)作用域,也就是說for,if,while等語句是不會創(chuàng)建...

    史占廣 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<