亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

var,let和const深入解析(一)

Hegel_Gu / 1219人閱讀

摘要:很顯然,局部作用域只能在內(nèi)部訪問(wèn)。第一次被稱為編譯狀態(tài),這一次的話,代碼中定義的變量就會(huì)提升。嚴(yán)格來(lái)說(shuō),我們變量的聲明已經(jīng)被移動(dòng)了位置,而不是聲明的相關(guān)代碼被移動(dòng)了位置。

es6有許多特別棒的特性,你可能對(duì)該語(yǔ)言的整體非常熟悉,但是你知道它在內(nèi)部是如何工作的嗎?當(dāng)我們知道它的內(nèi)部原理以后,我們使用起來(lái)也會(huì)更加的安心一些。這里我們想逐步的引導(dǎo)你,讓你對(duì)其有一個(gè)更深入,更淺顯的認(rèn)識(shí)。讓我們就先從es6中的變量開始講起吧。

let和const

在es6中新引入了兩種方式來(lái)申明變量,我們?nèi)匀豢梢允褂脧V為傳誦的var變量(然而你不應(yīng)該繼續(xù)使用它了,繼續(xù)閱讀來(lái)了解其中原因),但是現(xiàn)在我們有了兩種更牛的工具去使用:let和const。

let

let和var非常的相似,在使用方面,你可以使用完全相同的方式來(lái)聲明變量,例如:

let myNewVariable = 2;
var myOldVariable = 3;

console.log(myNewVariable); // 2
console.log(myOldVariable); // 3

但是實(shí)際上,他們之間有幾處明顯的不同。他們不僅僅是關(guān)鍵字變了,而且實(shí)際上它還讓會(huì)簡(jiǎn)化我們的一些工作,防止一些奇怪的bug,其中這些不同點(diǎn)是:

let是塊狀作用域(我將會(huì)在文章后面著重講一下作用域相關(guān)的東西),而var是函數(shù)作用域。

let不能在定義之前訪問(wèn)該變量(var是可以的,它確實(shí)是js世界中許多bug和困擾的源頭)。

let不能被重新定義。

在我們講解這些不同點(diǎn)之前,首先我們看一個(gè)更酷的變量:const

const

const和let非常像(跟var相比來(lái)說(shuō),他們之間有許多相同點(diǎn)),但是他們有一個(gè)主要的不同點(diǎn):let可以重新賦值,但是const不能。因此const定義的變量只能有一個(gè)值,并且這個(gè)值在聲明的時(shí)候就會(huì)被賦值。因此我們來(lái)看下下面的例子。

const myConstVariable = 2;
let myLetVariable = 3;

console.log(myConstVariable); // 2
myLetVariable = 4;  // ok
myConstVariable = 5;  //wrong - TypeError thrown

但是const是完全不可變的嗎?

有一個(gè)常見的問(wèn)題:雖然變量不能被重新賦值,但是也不能讓他們真正的變?yōu)椴豢勺兊臓顟B(tài)。如果const變量有一個(gè)數(shù)組或者對(duì)象作為其值的話,你可能會(huì)像下面的代碼一樣改變它的值。

const myConstObject = {mutableProperty: 2};

// myConstObject = {}; - TypeError
myConstObject.mutableProperty = 3; //ok
console.log(myConstObject.mutableProperty); // 3
const myConstArray = [1];

// myConstArray = []; - TypeError
myConstArray.push(2) //ok
console.log(myConstArray); // [1, 2]

當(dāng)然你不能用原始數(shù)據(jù)類型的值,比如string,number,boolean等,因?yàn)樗麄儽举|(zhì)上是不可變的。

真正的不可變

如果你想讓我們的變量真正的不可變的話,可以使用Object.freeze(), 它可以讓你的對(duì)象保持不可變。不幸的是,他僅僅是淺不可變,如果你對(duì)象里嵌套著對(duì)象的話,它依然是可變的。

const myConstNestedObject = {
  immutableObject: {
    mutableProperty: 1
  }
};

Object.freeze(myConstNestedObject);

myConstNestedObject.immutableObject = 10; // won"t change
console.log(myConstNestedObject.immutableObject); // {mutableProperty: 1}
myConstNestedObject.immutableObject.mutableProperty = 10; // ok
console.log(myConstNestedObject.immutableObject.mutableProperty); // 10

變量的作用域

在介紹了一些基礎(chǔ)知識(shí)以后,下面我們要進(jìn)入一個(gè)更高級(jí)的話題?,F(xiàn)在我們要開始講解es5和es6變量中的第一個(gè)不同-作用域

注意:下面的例子都用的是let,它的規(guī)則在const上同樣也適用

全局變量和函數(shù)作用域變量

在js中,究竟什么是作用域呢?本文不會(huì)給出一個(gè)關(guān)于作用域的完整解釋。簡(jiǎn)單來(lái)說(shuō),變量的作用域決定了變量的可用位置。從不同的角度來(lái)看,可以說(shuō)作用域是你可以在特定區(qū)域內(nèi)使用的那些變量(或者是函數(shù))的聲明。作用域可以是全局的(因此在全局作用域中定義的變量可以在你代碼中任何部分訪問(wèn))或者是局部的。

很顯然,局部作用域只能在內(nèi)部訪問(wèn)。在ES6以前,它僅僅允許一種方式來(lái)定義局部作用域 - function,咱們來(lái)看一下下面的例子:

// global scope
var globalVariable = 10;

function functionWithVariable() {
  // local scope
  var localVariable = 5;
  console.log(globalVariable);  // 10
  console.log(localVariable);   // 5
}

functionWithVariable();

//global scope again
console.log(globalVariable);  // 10
console.log(localVariable);   // undefined

上面的例子中,變量globalVariable是全局變量,所以它可以在我們代碼中的函數(shù)內(nèi)或者是其他區(qū)域內(nèi)被訪問(wèn)到,但是變量localVariable定義在函數(shù)內(nèi),所以它只在函數(shù)內(nèi)可訪問(wèn)。

因此,所有在函數(shù)內(nèi)創(chuàng)建的內(nèi)容都可以在函數(shù)內(nèi)被訪問(wèn)到,包括函數(shù)內(nèi)部里所有的嵌套函數(shù)(可能會(huì)被嵌套多層)。在這里可能要感謝閉包了,但是在文章里我們并不打算介紹它。不過(guò)請(qǐng)繼續(xù)關(guān)注,因?yàn)槲覀冊(cè)谖磥?lái)的博文中,會(huì)更多的介紹它。

提升

簡(jiǎn)單來(lái)說(shuō),提升是一種吧所有的變量和函數(shù)聲明“移動(dòng)”到作用域的最前面的機(jī)制。讓我們看一下下面的例子。

function func() {
  console.log(localVariable);   // undefined
  var localVariable = 5;

  console.log(localVariable);   // 5
}

func();

它為什么依然會(huì)正常工作呢?我們還沒有定義這個(gè)變量,但是它依然通過(guò)console.log()打印出了undefined。為什么不會(huì)報(bào)出一個(gè)變量未定義的錯(cuò)誤呢?讓我們?cè)僮屑?xì)看一下。

編譯變量

Javascript解析器要遍歷這個(gè)代碼兩次。第一次被稱為編譯狀態(tài),這一次的話,代碼中定義的變量就會(huì)提升。在他之后,我們的代碼就變成類似于下面的這樣子的(我已經(jīng)做了一些簡(jiǎn)化,只展示出相關(guān)的部分)。

function func() {
  var localVariable = undefined;

  console.log(localVariable); // undefined
  localVariable = 5;

  console.log(localVariable); // 5
}

func();

我們看到的結(jié)果是,我們的變量localVariable已經(jīng)被移動(dòng)到func函數(shù)的作用域的最前面。嚴(yán)格來(lái)說(shuō),我們變量的聲明已經(jīng)被移動(dòng)了位置,而不是聲明的相關(guān)代碼被移動(dòng)了位置。我們使用這個(gè)變量并打印出來(lái)。它是undefined是因?yàn)槲覀冞€沒有定義它的值,它默認(rèn)使用的undefined。

提升的例子 - 會(huì)出什么問(wèn)題

來(lái)讓我們看一個(gè)令人討厭的例子,我們的作用域范圍對(duì)于我們來(lái)說(shuō),是弊大于利的。也不是說(shuō)函數(shù)作用域是不好的。而是說(shuō)我們必須要警惕一些由于提升而引起的一些陷進(jìn)。我們來(lái)看看下面的代碼:

var callbacks = [];
for (var i = 0; i < 4; i++) {
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();

你認(rèn)為輸出的值是多少呢?你猜可能是0 1 2 3,是嗎?如果是的話,對(duì)于你來(lái)說(shuō),可能會(huì)有一些驚喜。實(shí)際上,他真實(shí)的結(jié)果是4 4 4 4。等等,它到底發(fā)生了什么?我們來(lái)“編譯”一下代碼,代碼現(xiàn)在看起來(lái)就像這樣:

var callbacks;
var i;

callbacks = [];
for (i = 0; i < 4; i++) {
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();

你看出問(wèn)題所在了嗎?變量i在整個(gè)作用域下都是可以被訪問(wèn)到的,它不會(huì)被重新定義。它的值只會(huì)在每次的迭代中不斷地被改變。然后呢,當(dāng)我們隨后想通過(guò)函數(shù)調(diào)用打印它的值得時(shí)候,他實(shí)際上只有一個(gè)值 - 就是在最后一次循環(huán)賦給的那個(gè)值。

我們只能這樣了嗎?不是的

Let和Const的拯救

除了定義變量的新方式以外,還引入了一種新的作用域:塊級(jí)作用域。塊就是由花括號(hào)括起來(lái)的所有的內(nèi)容。所以它可以是if,while或者是for聲明中的花括號(hào),也可以是多帶帶的一個(gè)花括號(hào)甚至是一個(gè)函數(shù)(對(duì),函數(shù)作用域是塊狀作用域)。let和const是塊作用域。意味著無(wú)論你在塊中無(wú)論定義了什么變量,什么時(shí)候定義的,它都不會(huì)跑到塊作用域外面去。我們來(lái)看一下下面的例子:

function func() {
  // function scope
  let localVariable = 5;
  var oldLocalVariable = 5;

  if (true) {
    // block scope
    let nestedLocalVariable = 6;
    var oldNestedLocalVariable = 6;

    console.log(nestedLocalVariable); // 6
    console.log(oldNestedLocalVariable); // 6
  }

  // those are stil valid
  console.log(localVariable); // 5
  console.log(oldLocalVariable); // 5
  // and this one as well
  console.log(oldNestedLocalVariable); // 6
  // but this on isn"t
  console.log(nestedLocalVariable); // ReferenceError: nestedLocalVariable is not defined

你能看出來(lái)差別嗎?你能看出來(lái)怎么使用let來(lái)解決早些時(shí)候提出問(wèn)題的嗎?我們的for循環(huán)包含一組花括號(hào),所以它是塊作用域。所以如果在定義循環(huán)變量的時(shí)候,使用的是let或者是const來(lái)代替var的話,代碼會(huì)轉(zhuǎn)為下面的形式。注意:我實(shí)際上已經(jīng)簡(jiǎn)化了很多,不過(guò)我確定你能理解我的意思。

let callbacks = [];
for (; i < 4; i++) {
  let i = 0 //, 1, 2, 3
  callbacks.push(() => console.log(i));
}

callbacks[0]();
callbacks[1]();
callbacks[2]();
callbacks[3]();

現(xiàn)在的每一次循環(huán)都有它自己的變量定義,所以變量不會(huì)被重寫,我們確信這行代碼可以完成讓他做的任何事情。

這是這一部分結(jié)束的例子,但是我們?cè)倏匆幌孪旅娴睦樱蚁嘈拍忝靼状蛴〕鰜?lái)的值的原因,以及對(duì)應(yīng)的表現(xiàn)是什么。

function func() {
  var functionScopedVariable = 10;
  let blockScopedVariable = 10;

  console.log(functionScopedVariable);  // 10
  console.log(blockScopedVariable);  // 10
  if (true) {
    var functionScopedVariable = 5;
    let blockScopedVariable = 5;

    console.log(functionScopedVariable);  // 5
    console.log(blockScopedVariable);  // 5
  }

  console.log(functionScopedVariable);  // 5
  console.log(blockScopedVariable);  // 10
}

func();

本文翻譯自:

https://blog.pragmatists.com/...

本文轉(zhuǎn)載自:http://www.lht.ren/article/15/

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/101656.html

相關(guān)文章

  • Javascript基礎(chǔ)之-var,letconst深入解析(二)

    摘要:規(guī)范對(duì)其是這樣進(jìn)行的描述的。聲明定義了在正在運(yùn)行的執(zhí)行上下文作用域內(nèi)的變量環(huán)境中的變量。在執(zhí)行時(shí),由帶有的定義的變量被賦其設(shè)定項(xiàng)的的值。由于變量已經(jīng)被聲明,是可訪問(wèn)的,因此會(huì)打印出正確的結(jié)果。 你想在在變量聲明之前就使用變量?以后再也別這樣做了。 新的聲明方式(let,const)較之之前的聲明方式(var),還有一個(gè)區(qū)別,就是新的方式不允許在變量聲明之前就使用該變量,但是var是可以...

    XiNGRZ 評(píng)論0 收藏0
  • 深入理解ES6 () 塊級(jí)綁定

    摘要:聲明聲明的語(yǔ)法與的語(yǔ)法一致??偨Y(jié)文章都是以深入理解讀書筆記形式,大部分引用書中的定義,加上作者的理解,樣例也做了調(diào)整,所有樣例都可以放到里運(yùn)行親自嘗試。 1.變量提升 使用 var 關(guān)鍵字聲明的變量,無(wú)論其實(shí)際聲明位置在何處,都會(huì)被視為聲明于所在函數(shù)的 頂部(如果聲明不在任意函數(shù)內(nèi),則視為在全局作用域的頂部)。這句話從字面上不難理解。 但是他是怎樣一個(gè)過(guò)程,為什么會(huì)這樣。當(dāng)你代...

    KunMinX 評(píng)論0 收藏0
  • 深入理解letvar的區(qū)別(暫時(shí)性死區(qū))?。?!

    摘要:會(huì)出現(xiàn)這樣的情況是因?yàn)閾碛袝簳r(shí)性死區(qū)。規(guī)定暫時(shí)性死區(qū)和語(yǔ)句不出現(xiàn)變量提升,主要是為了減少運(yùn)行時(shí)錯(cuò)誤,防止在變量聲明前就使用這個(gè)變量,從而導(dǎo)致意料之外的行為。 首先我們應(yīng)該知道js引擎在讀取js代碼時(shí)會(huì)進(jìn)行兩個(gè)步驟: 第一個(gè)步驟是解釋。 第二個(gè)步驟是執(zhí)行。 所謂解釋就是會(huì)先通篇掃描所有的Js代碼,然后把所有聲明提升到頂端,第二步是執(zhí)行,執(zhí)行就是操作一類的。 我們先來(lái)看個(gè)簡(jiǎn)單的變量提升...

    tanglijun 評(píng)論0 收藏0
  • 深入編譯器——第部分:詞法解析Scanner(介紹ECMAScript的詞法規(guī)范TypeScr

    摘要:詞法分析對(duì)構(gòu)成源程序的字符流進(jìn)行掃描然后根據(jù)構(gòu)詞規(guī)則識(shí)別單詞也稱單詞符號(hào)或符號(hào)。語(yǔ)義分析是編譯過(guò)程的一個(gè)邏輯階段語(yǔ)義分析的任務(wù)是對(duì)結(jié)構(gòu)上正確的源程序進(jìn)行上下文有關(guān)性質(zhì)的審查進(jìn)行類型審查,審查抽象語(yǔ)法樹是否符合該編程語(yǔ)言的規(guī)則。 1. 文章的內(nèi)容和主題 我對(duì)編譯器的深入了解起源于一條推特中的問(wèn)題:Angular是如何用Angular預(yù)先編譯器(AOT)對(duì)靜態(tài)代碼進(jìn)行解析工作的。在進(jìn)行一些...

    pingan8787 評(píng)論0 收藏0
  • 深入了解babel(二)

    摘要:接著上一篇文章深入了解一的處理步驟的三個(gè)主要處理步驟分別是解析,轉(zhuǎn)換,生成。模塊是的代碼生成器,它讀取并將其轉(zhuǎn)換為代碼和源碼映射抽象語(yǔ)法樹抽象語(yǔ)法樹在以上三個(gè)神器中都出現(xiàn)過(guò),所以對(duì)于編譯器來(lái)說(shuō)至關(guān)重要。 接著上一篇文章《深入了解babel(一)》 Babel 的處理步驟 Babel 的三個(gè)主要處理步驟分別是: 解析(parse),轉(zhuǎn)換(transform),生成(generate)。對(duì)...

    ChanceWong 評(píng)論0 收藏0

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<