欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript 作用域scope簡單匯總

 更新時間:2019年10月23日 14:46:41   作者:得閑讀書  
這篇文章主要介紹了JavaScript 作用域scope簡單匯總,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

什么是作用域

程序的執(zhí)行,離不開作用域,也必須在作用域中才能將代碼正確的執(zhí)行。

所以作用域到底是什么,通俗的說,可以這樣理解:作用域就是定義變量的位置,是變量和函數(shù)的可訪問范圍,控制著變量和函數(shù)的可見性和生命周期。

而JavaScript中的作用域,在ES6之前和ES6之后,有兩種不同的情況。

ES6之前,JavaScript作用域有兩種:函數(shù)作用域和全局作用域。

ES6之后,JavaScript新增了塊級作用域。

作用域的特性

在JavaScript變量提升的討論中,我們其實是缺少了一個作用域的概念的,變量提升其實也是針對在同一作用域中的代碼來說的。

對編譯器的了解,讓我們明白,對于一段代碼【var a = 10】變量的賦值操作,其實是包含了兩個過程:

1、變量的聲明和隱式賦值(var a = undefined),這個階段在編譯時

2、變量的賦值(a = 10),這個階段在運行時

先看一下如下代碼:

var flag = true;

if(flag) {
  var someStr = 'flag is true';
}

function doSomething() {
  var someStr = 'in doSomething';
  var otherStr = 'some other string';
  console.log(someStr);
  console.log(flag);
}

doSomething();

for(var i = 0; i < 10; i++) {
  console.log(i);
}

console.log(i);

{
  var place = 'i do not want to be visited';
}

那么這一些代碼在編譯之后,執(zhí)行之前,根據(jù)變量提升的機制,我們可以知道應(yīng)該是下面這個樣子:

function doSomething() { // 函數(shù)優(yōu)先提升
  // 提升隱式賦值
  var someStr = undefined; 
  var otherStr = undefined; 

  someStr = 'in doSomething';
  otherStr = 'some other string';

  console.log(someStr);
  console.log(flag);
}

// 隱式賦值和提升
var flag = undefined; 
var someStr = undefined;
var i = undefined;
var place = undefined;

flag = true;

if(flag) {
  someStr = 'flag is true';
}

for(i = 0; i < 10; i++) {
  console.log(i);
}

doSomething();

console.log(i);

{
  place = 'i do not want to be visited';
}

因為變量的提升特性,以及無塊級作用域的概念,所以代碼中在同一個作用域中變量和函數(shù)的定義,在編譯階段都會提升到頂部。

通過上述代碼,我們大體上可以得出作用域的特性:

第一、內(nèi)部作用域和外部作用域是嵌套關(guān)系。外部作用域完全包含內(nèi)部作用域。

第二、內(nèi)部作用域可訪問外部作用域的變量,但是外部作用域不能訪問內(nèi)部作用域的變量,(鏈式繼承,向上部作用域查找)。

第三、變量提升是在同一個作用域內(nèi)部出現(xiàn)的。

第四、作用域用于編譯器在編譯代碼時候,確定變量和函數(shù)聲明的位置。

塊級作用域

上述代碼,在ES6+的環(huán)境中運行,也是和ES6之前是相同的結(jié)果,但是ES6不是引用了塊級作用域嗎,為什么大括號塊內(nèi)的代碼還是會出現(xiàn)和之前一樣的編譯方式呢?

那么,ES6中的塊級作用域到底是什么?

let & const

利用var定義的變量,具有提升的性質(zhì),可能會影響代碼的執(zhí)行結(jié)果。

這是var定義變量的缺陷,那么如何規(guī)避這種缺陷呢?在ES6中,設(shè)計出來了let和const來重新定變量。

但是,由于JavaScript標準定義的非常早,1995年5月JavaScript方案定義,1996年微軟提供了JavaScript解決方案JScript。而網(wǎng)景公司為了同微軟競爭,神情了JavaScript標準,于是,1997年6月第一個國際標準ECMA-262便頒布了。

C語言標準化的過程卻是將近二十年后才頒布。

所以,我們以后設(shè)計的語言既要兼容var也要有自己的塊級作用域,讓var和let以及const在引擎做到兼容。

所以,我們定義塊級作用域的標準,只能從定義變量的方式入手,而不是直接一個{}塊就可以解決。

先讓我們看一下下面代碼:

var name = 'someName';

function doSomething(){
  console.log(name);
  if(true) {
    var name = 'otherName';
  }
}
doSomething();
結(jié)果:undefined

產(chǎn)生這個結(jié)果的原因是我們函數(shù)內(nèi)部的變量提升,覆蓋了外部作用域的變量,也就是說,其實打印出來的值是doSomething函數(shù)中的變量聲明的值。

但是這樣卻并不符合塊級作用域的預期,如果有許多類似代碼,理解起來也會相當困難。如果將代碼用ES6方式改寫:

let name = 'someName';

function doSomething(){
  console.log(name);
  if(true) {
    let name = 'otherName';
  }
}

doSomething();

結(jié)果:'someName'

從運行結(jié)果看,我們真正的做到了塊級作用域應(yīng)該有的效果,那么let和const又是如何支持塊作用域的呢?

執(zhí)行上下文

先想想一下JavaScript中的一個作用域兩個執(zhí)行上下文中的編譯過程中的環(huán)境:

變量環(huán)境:編譯階段var聲明存放的位置(一個大對象)。

詞法環(huán)境:我們代碼書寫的位置,也是let和const的初始化位置(代碼按詞法環(huán)境順序執(zhí)行,按照{(diào)}劃分的棧結(jié)構(gòu))。

而在編譯階段,我們將var定義的變量全都在編譯過程在變量環(huán)境初始化為undefined,但是用let和const定義的變量,其實他們并未在變量環(huán)境初始化,而是在詞法環(huán)境初始化,也就是執(zhí)行代碼位置初始化。

詞法環(huán)境的特點:按照{(diào)}劃分的一個棧結(jié)構(gòu)。

變量查找方式

JavaScript中變量查找的方式:沿著詞法環(huán)境的棧頂向下查找,找不到的變量去變量環(huán)境中查找,這樣就形成了先查找代碼塊中的變量,再查找提升之后的變量環(huán)境,這樣就形成了塊級作用域的概念。

上面的代碼形成兩種環(huán)境的情況如下:

一、全局環(huán)境的執(zhí)行上下文

變量環(huán)境:函數(shù)聲明function doSomething() { … }

詞法環(huán)境棧:執(zhí)行到let name = ‘someName';讓語句name = ‘someName'入棧。

二、doSomething的執(zhí)行上下文(被全局環(huán)境包裹)

變量環(huán)境:無

詞法環(huán)境棧情況:執(zhí)行到let name = ‘otherName',語句的時候,name = ‘other'才會入棧;

JavaScript代碼執(zhí)行方式

執(zhí)行doSomething的時候,還未執(zhí)行l(wèi)et name = ‘otherName',所以,此時doSomething的詞法環(huán)境中并未有name = ‘otherName',這個時候查找,只能向外部作用域查找(全局作用域)

此時查找到全局作用域name = ‘someName'所以此時就打印了someName

代碼接著執(zhí)行到了if語句內(nèi)部,才會將name = ‘otherName'入棧,但是此時因為語句已經(jīng)執(zhí)行完畢,所以也就無關(guān)痛癢了。

JavaScript也就通過這種方式,實現(xiàn)了塊級別作用域。

總結(jié)

JavaScript中的作用域總的來說,分為塊級作用域、函數(shù)作用域、全局作用域。

而每個作用域都會創(chuàng)建自身的執(zhí)行上下文,每一個執(zhí)行上下文又分為了變量環(huán)境和詞法環(huán)境兩部分。

塊級作用域的實現(xiàn),其實是根據(jù)定義的let和const聲明的變量放置在詞法環(huán)境棧中這一特性來實現(xiàn)。

這一特性被社區(qū)的人叫做‘暫時性死區(qū)',但是在JavaScript標準中并未有這個概念。

只有理解了作用域的概念,才能真正明白JavaScript的執(zhí)行機制,才能減少我們因為變量定義等發(fā)生的錯誤。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 使用3D引擎threeJS實現(xiàn)星空粒子移動效果

    使用3D引擎threeJS實現(xiàn)星空粒子移動效果

    這篇文章主要為大家詳細介紹了使用3D引擎threeJS實現(xiàn)星空粒子移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • JS target與currentTarget區(qū)別說明

    JS target與currentTarget區(qū)別說明

    target在事件流的目標階段;currentTarget在事件流的捕獲,目標及冒泡階段。只有當事件流處在目標階段的時候,兩個的指向才是一樣的,而當處于捕獲和冒泡階段的時候,target指向被單擊的對象而currentTarget指向當前事件活動的對象(一般為父級)。
    2011-08-08
  • 利用Plupload.js解決大文件上傳問題, 帶進度條和背景遮罩層

    利用Plupload.js解決大文件上傳問題, 帶進度條和背景遮罩層

    本篇文章主要介紹了c#+Plupload.js解決大容量文件上傳問題, 帶進度條和背景遮罩層,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • js 瀏覽器事件介紹

    js 瀏覽器事件介紹

    瀏覽器事件指載入文檔直到該文檔被關(guān)閉期間的瀏覽器事件,如瀏覽器載入文檔事件onload、關(guān)閉該文檔事件onunload、瀏覽器失去焦點事件onblur、獲得焦點事件onfocus 等
    2012-03-03
  • JS原生數(shù)據(jù)雙向綁定實現(xiàn)代碼

    JS原生數(shù)據(jù)雙向綁定實現(xiàn)代碼

    本文通過實例代碼給大家介紹了JS原生數(shù)據(jù)雙向綁定問題,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的的朋友參考下吧
    2017-08-08
  • Javascript玩轉(zhuǎn)繼承(一)

    Javascript玩轉(zhuǎn)繼承(一)

    最近一直在學Javascript,打算寫一些文章,算做自己的學習心得吧,也可以算是學習筆記。沒有系統(tǒng)的知識點,太基礎(chǔ)的不想寫,主要是寫一些自己覺得有價值的地方
    2014-05-05
  • JS實現(xiàn)提示效果彈出及延遲隱藏的功能

    JS實現(xiàn)提示效果彈出及延遲隱藏的功能

    這篇文章主要介紹了JS實現(xiàn)提示效果彈出及延遲隱藏的功能,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08
  • 微信小程序?qū)崿F(xiàn)tab切換效果

    微信小程序?qū)崿F(xiàn)tab切換效果

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)tab切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 起點頁面?zhèn)髦礿s,有空研究學習下

    起點頁面?zhèn)髦礿s,有空研究學習下

    起點上的頁面?zhèn)髦礿s,有空研究下
    2010-01-01
  • JS實現(xiàn)表單中點擊小眼睛顯示隱藏密碼框中的密碼

    JS實現(xiàn)表單中點擊小眼睛顯示隱藏密碼框中的密碼

    這篇文章主要介紹了JS實現(xiàn)表單中點擊小眼睛顯示隱藏密碼框中的密碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考價值,需要的朋友可以參考下
    2020-04-04

最新評論