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

資訊專欄INFORMATION COLUMN

ES6系列之 let 和 const

libxd / 2788人閱讀

摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。這在語法上,稱為暫時(shí)性死區(qū),簡稱。這表明函數(shù)內(nèi)部的變量與循環(huán)變量不在同一個(gè)作用域,有各自多帶帶的作用域。系列文章系列文章地址

為什么需要塊級作用域

ES5 只有全局作用域和函數(shù)作用域,沒有塊級作用域,這帶來很多不合理的場景。

通過var聲明變量存在變量提升:

if (condition) {
    var value = 1
}
console.log(value)

初學(xué)者可能會(huì)認(rèn)為當(dāng)變量condition為true時(shí),才會(huì)創(chuàng)建value。當(dāng)condition為false時(shí),不會(huì)創(chuàng)建value,結(jié)果應(yīng)該是報(bào)錯(cuò)。然而因?yàn)镴avaScript存在變量提升的概念,代碼等同于:

var value
if (condition) {
    value = 1
}
console.log(value) // undefined

所有當(dāng)condition為false,輸入結(jié)果為undefined。

ES5 只有全局作用域和函數(shù)作用域,其中變量提升也分成兩種情況:一種全局聲明的變量,提升會(huì)在全局最上面,上面就屬于全局變量聲明;一種是函數(shù)中聲明的變量,提升在函數(shù)的最上方:

function fn() {
    var value
    if (condition) {
        value = 1
    }
    console.log(value) // undefined
}

console.log(value) // Uncaught ReferenceError: value is not defined

所有當(dāng)condition為false,函數(shù)內(nèi)輸入結(jié)果為undefined,函數(shù)輸入就會(huì)報(bào)錯(cuò)Uncaught ReferenceError: value is not defined。函數(shù)的變量提升是根據(jù)最近的外層函數(shù)提升,沒有函數(shù)就為全局下提升。

為規(guī)范變量使用控制,ECMAScript 6 引入了塊級作用域。
塊級作用域就是 {} 之間的區(qū)域

let 和 const

我們來整理一下 let 和 const 的特點(diǎn):

不存在變量提升

if(condition) {
    let value = 1
}
console.log(value) // Uncaught ReferenceError: value is not defined

不管 conditon 為 true 或者 false ,都無法輸出value,結(jié)果為 Uncaught ReferenceError: value is not defined

重復(fù)聲明報(bào)錯(cuò)

let value = 1
let value = 2

重復(fù)聲明同一個(gè)變量,會(huì)直接報(bào)錯(cuò) Uncaught SyntaxError: Identifier "value" has already been declared

不綁定在全局作用域上

var value = 1
console.log(window.value) // 1

在來看一下let聲明:

let value = 1
console.log(window.value) // undefined
let 和 const 的區(qū)別:

const聲明一個(gè)只讀的常量。一旦聲明,常量的值就不能改變。

const value = 1

value = 2 // Uncaught TypeError: Assignment to constant variable.

上面代碼表明改變常量的值會(huì)報(bào)錯(cuò)。

const聲明的變量不得改變值,這意味著,const一旦聲明變量,就必須立即初始化,不能留到以后賦值。

const foo;
// SyntaxError: Missing initializer in const declaration

上面代碼表示,對于const來說,只聲明不賦值,就會(huì)報(bào)錯(cuò)。

對于對象的變量,變量指向是數(shù)據(jù)指向的內(nèi)存地址。const只能保證數(shù)據(jù)指向內(nèi)存地址不能改變,并不能保證該地址下數(shù)據(jù)不變。

const data = {
    value: 1
}

// 更改數(shù)據(jù)
data.value = 2
console.log(data.value) // 2

// 更改地址
data = {} // Uncaught TypeError: Assignment to constant variable.

上述代碼中,常量 data 存儲(chǔ)的是一個(gè)地址,這里地址指向一個(gè)對象。不可變的只是這個(gè)地址,即不能將 data 指向另一個(gè)地址,但是對象本身是可以變的,所以依然為其更改或添加新屬性。

暫時(shí)性死區(qū)

在代碼塊內(nèi),使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時(shí)性死區(qū)”(temporal dead zone,簡稱 TDZ)。

let 和 const 聲明的變量不會(huì)被提升到作用域頂部,如果在聲明之前訪問這些變量,會(huì)導(dǎo)致報(bào)錯(cuò):

console.log(typeof value); // Uncaught ReferenceError: value is not defined
let value = 1;

這是因?yàn)?JavaScript 引擎在掃描代碼發(fā)現(xiàn)變量聲明時(shí),要么將它們提升到作用域頂部(遇到 var 聲明),要么將聲明放在 TDZ 中(遇到 let 和 const 聲明)。訪問 TDZ 中的變量會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。只有執(zhí)行過變量聲明語句后,變量才會(huì)從 TDZ 中移出,然后方可訪問。

看似很好理解,不保證你不犯錯(cuò):

var value = "global";

// 例子1
(function() {
    console.log(value);

    let value = "local";
}());

// 例子2
{
    console.log(value);

    const value = "local";
};

兩個(gè)例子中,結(jié)果并不會(huì)打印 "global",而是報(bào)錯(cuò) Uncaught ReferenceError: value is not defined,就是因?yàn)?TDZ 的緣故。

常見面試題
for(var i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i)
    })
}
// 3
// 3
// 3

上述代碼中,我們期望輸出0,1,2三個(gè)值,但是輸出結(jié)果是 3,3,3 ,不符合我們的預(yù)期。

解決方案如下:
使用閉包解法

for(var i = 0; i < 3; i++) {
    (function(i) {
        setTimeout(() => {
            console.log(i)
        })
    })(i)
}
// 0
// 1
// 2

ES6 的 let 解法

for(let i = 0; i < 3; i++) {
    setTimeout(() => {
        console.log(i)
    })
}
// 0
// 1
// 2

上述代碼中,變量 i 是 let 聲明的,當(dāng)前的i只在本輪循環(huán)有效,所以每一次循環(huán)的i其實(shí)都是一個(gè)新的變量,所以最后輸出的是0,1,2。你可能會(huì)問,如果每一輪循環(huán)的變量i都是重新聲明的,那它怎么知道上一輪循環(huán)的值,從而計(jì)算出本輪循環(huán)的值。這是因?yàn)?JavaScript 引擎內(nèi)部會(huì)記住上一輪循環(huán)的值,初始化本輪的變量i時(shí),就在上一輪循環(huán)的基礎(chǔ)上進(jìn)行計(jì)算.

另外,for循環(huán)還有一個(gè)特別之處,就是設(shè)置循環(huán)變量的那部分是一個(gè)父作用域,而循環(huán)體內(nèi)部是一個(gè)多帶帶的子作用域。

for (let i = 0; i < 3; i++) {
  let i = "abc";
  console.log(i);
}
// abc
// abc
// abc

上面代碼正確運(yùn)行,輸出了 3 次abc。這表明函數(shù)內(nèi)部的變量i與循環(huán)變量i不在同一個(gè)作用域,有各自多帶帶的作用域。

如果嘗試將 let 改成 const 定義:

for (const i = 0; i < 3; i++) {
  console.log(i);
}
// 0
// Uncaught TypeError: Assignment to constant variable.

上述代碼中,會(huì)先輸出一次 0,然后代碼就會(huì)報(bào)錯(cuò)。這是由于for循環(huán)的執(zhí)行順序造成的,i 定義為 0,然后執(zhí)行 i < 3比較,符合條件執(zhí)行循環(huán)主體,輸出一次 0, 然后執(zhí)行 i++,由于 i 使用const定義的只讀變量,代碼執(zhí)行報(bào)錯(cuò)。

說完了普通的for循環(huán),我們還有for…in循環(huán)呢~

那下面的結(jié)果是什么呢?

const object = {a: 1, b: 1, c: 1};
for (const key in object) {
    console.log(key)
}
// a
// b
// c

上述代碼中,雖然使用 const 定義 key 值,但是代碼中并沒有嘗試修改 key 值,代碼正常執(zhí)行,這也是普通for循環(huán)和for…in循環(huán)的區(qū)別。

Babel編譯

在 Babel 中是如何編譯 let 和 const 的呢?我們來看看編譯后的代碼:

let value = 1;

編譯為:

var value = 1;

我們可以看到 Babel 直接將 let 編譯成了 var,如果是這樣的話,那么我們來寫個(gè)例子:

if (false) {
    let value = 1;
}
console.log(value); // Uncaught ReferenceError: value is not defined

如果還是直接編譯成 var,打印的結(jié)果肯定是 undefined,然而 Babel 很聰明,它編譯成了:

if (false) {
    var _value = 1;
}
console.log(value);

我們再寫個(gè)直觀的例子:

let value = 1;
{
    let value = 2;
}
value = 3;
var value = 1;
{
    var _value = 2;
}
value = 3;

本質(zhì)是一樣的,就是改變量名,使內(nèi)外層的變量名稱不一樣。

那像 const 的修改值時(shí)報(bào)錯(cuò),以及重復(fù)聲明報(bào)錯(cuò)怎么實(shí)現(xiàn)的呢?

其實(shí)就是在編譯的時(shí)候直接給你報(bào)錯(cuò)……

那循環(huán)中的 let 聲明呢?

var funcs = [];
for (let i = 0; i < 10; i++) {
    funcs[i] = function () {
        console.log(i);
    };
}
funcs[0](); // 0

Babel 巧妙的編譯成了:

var funcs = [];

var _loop = function _loop(i) {
    funcs[i] = function () {
        console.log(i);
    };
};

for (var i = 0; i < 10; i++) {
    _loop(i);
}
funcs[0](); // 0
項(xiàng)目實(shí)踐

在我們實(shí)際項(xiàng)目開發(fā)過程中,應(yīng)該默認(rèn)使用 let 定義可變的變量,使用 const 定義不可變的變量,而不是都使用 var 來定義變量。同時(shí),變量定義位置也有一定區(qū)別,使用
var 定義變量都會(huì)在全局頂部或者函數(shù)頂部定義,防止變量提升造成的問題,對于使用 let 和 const 定義遵循就近原則,即變量定義在使用的最近的塊級作用域中。

ES6系列文章

ES6系列文章地址:https://github.com/changming-...

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

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

相關(guān)文章

  • ES6 系列 let const

    摘要:塊級作用域存在于函數(shù)內(nèi)部塊中字符和之間的區(qū)域和塊級聲明用于聲明在指定塊的作用域之外無法訪問的變量。和都是塊級聲明的一種。值得一提的是聲明不允許修改綁定,但允許修改值。這意味著當(dāng)用聲明對象時(shí)沒有問題報(bào)錯(cuò)臨時(shí)死區(qū)臨時(shí)死區(qū),簡寫為。 塊級作用域的出現(xiàn) 通過 var 聲明的變量存在變量提升的特性: if (condition) { var value = 1; } console.lo...

    PascalXie 評論0 收藏0
  • ES6 系列 WeakMap

    摘要:一個(gè)對象若只被弱引用所引用,則被認(rèn)為是不可訪問或弱可訪問的,并因此可能在任何時(shí)刻被回收。也就是說,一旦不再需要,里面的鍵名對象和所對應(yīng)的鍵值對會(huì)自動(dòng)消失,不用手動(dòng)刪除引用。如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤剑垊?wù)必給予指正,十分感謝。 前言 我們先從 WeakMap 的特性說起,然后聊聊 WeakMap 的一些應(yīng)用場景。 特性 1. WeakMap 只接受對象作為鍵名 const map = ...

    CollinPeng 評論0 收藏0
  • ES6 系列模板字符串

    摘要:最終的代碼如下第二版假設(shè)有這樣一段為了保持可讀性,我希望最終輸入的樣式為其實(shí)就是匹配每行前面的空格,然后將其替換為空字符串。 基礎(chǔ)用法 let message = `Hello World`; console.log(message); 如果你碰巧要在字符串中使用反撇號,你可以使用反斜杠轉(zhuǎn)義: let message = `Hello ` World`; console.log(mes...

    Travis 評論0 收藏0
  • ES6 完全使用手冊

    摘要:前言這里的泛指之后的新語法這里的完全是指本文會(huì)不斷更新這里的使用是指本文會(huì)展示很多的使用場景這里的手冊是指你可以參照本文將項(xiàng)目更多的重構(gòu)為語法此外還要注意這里不一定就是正式進(jìn)入規(guī)范的語法。 前言 這里的 ES6 泛指 ES5 之后的新語法 這里的 完全 是指本文會(huì)不斷更新 這里的 使用 是指本文會(huì)展示很多 ES6 的使用場景 這里的 手冊 是指你可以參照本文將項(xiàng)目更多的重構(gòu)為 ES6...

    kgbook 評論0 收藏0
  • ES6系列文章 塊級作用域

    摘要:聲明之函數(shù)作用域和全局作用域。塊級作用域不能重復(fù)聲明臨時(shí)性死區(qū)等特性用來解決變量存在的種種問題。塊級作用域終于在外面訪問不到了。一些常量聲明使用聲明的變量名全部大寫。 ES5之前javascript語言只有函數(shù)作用域和全局作用域,使用var來聲明變量,var聲明的變量還存在變量提升使人困惑不已。我們先來復(fù)習(xí)一下ES5的var聲明,再對比學(xué)習(xí)let和const 。 var var聲明之函...

    趙連江 評論0 收藏0

發(fā)表評論

0條評論

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