ES6走走看看—由塊級做用域引出的一場變革

持續更新的github筆記,連接地址:Front-End-Basics html

此篇文章的筆記地址:字符到底發生了什麼變化 git

ES6走走看看系列,特別鳴謝奇舞讀書會~github


塊級做用域又稱詞法做用域,存在於:

  • 函數內部(函數做用域)
  • 塊中(字符 { 和 } 之間的區域)

注意:ES6容許塊級做用域任意嵌套瀏覽器

{{{{{{let text = 'Hello World!'}}}}}}

由於有了塊級做用域,而後咱們纔有繼續往下聊的可能。安全

一、 塊級聲明

塊級聲明是用於聲明在指定塊的做用域以外沒法訪問的變量。函數

二、 let聲明:用來聲明一個塊級做用域變量

一、 聲明的變量具備塊級做用域的特性spa

// 例子
function getValue (condition) {
    if (condition) {
        let value = 'blue';
        return value;
    }
    console.log(value)
    // 報錯 value is not defined
}
getValue()

二、 在同一個做用域內不能使用let聲明同名的變量code

// 不論是var,const或者let,新的let聲明以前同名的變量,都會報錯
var count = 30;
let count = 40;
// 報錯 Identifier 'count' has already been declared

// 函數形參和函數內部的let聲明變量重名,報錯
function test(value) {
    let value = 3;
}
test()
// 報錯 Identifier 'value' has already been declared

// 在不一樣的做用域聲明的變量重名是沒問題的
let count = 30;
if(true) {
  let count = 40;
  // 不一樣的做用域,不會報錯
}

三、 聲明沒有預解析,不存在變量提高,有「臨時死區」(TDZ)htm

從塊的開始到變量聲明這段的區域被稱爲臨時死區,ES6明確規定,若是區塊中存在let和const命令,則這個區塊對這些命令聲明的變量從一開始就造成封閉做用域,只要在聲明以前就使用這些變量(賦值,引用等等),就會報錯。對象

if(true) {
    console.log(typeof value);
    // 報錯 value is not defined

    let value = 'blue';
}

注意:TDZ是區域是「塊開始」到「變量聲明」,下面的例子不報錯

// typeof 說是相對安全,確實是,永遠拿不到想要的結果
console.log(typeof value); // 打印 undefined,沒有報錯
if(true) {
    let value = 'red';
}

三、 const聲明:聲明常量(如PI),值一旦被設定後不可更改

一、 常量聲明的值是不可變的

注意:const聲明的對象不容許修改綁定,但能夠修改該對象的屬性值。

const number = 6;
number = 5;
// 報錯 Assignment to constant variable

const obj = {number: 1};
obj.number = 2; // 不報錯

obj = {number: 3};
// 報錯 Assignment to constant variable

二、 由於常量聲明後值就不可更改了,因此聲明時必須賦值

// 有效的常量
const count = 30;

// 報錯 Missing initializer in const declaration
const name;

三、 聲明的常量具備塊級做用域的特性

if(true) {
    const number = 5;
}
console.log(number)
// 報錯 number is not defined

四、 在同一個做用域內不能使用const聲明同名的變量

var message = 'Hello';
let age = 25;

// 這兩條語句都會報錯
const message = 'Good';
const age = 30;

五、 聲明沒有預解析,不存在變量提高,有「臨時死區」(TDZ)


總結:一張表格

聲明方式 變量提高 做用域 是否須要初始值 重複定義
var 函數級 不須要 容許
let 塊級 不須要 不容許
const 塊級 須要 不容許

擴展:再提一下變量命名,不論是var、let、const聲明的變量名,能夠由數字,字母,下劃線及美圓符號組成,可是不能以數字開頭。美圓符號能夠放到任何一個位置,甚至單獨一個美圓符號。

四、 循環中的塊做用域綁定

循環中的let聲明
// 第一個對比
// before
for(var i = 0; i < 5; i++) {
    // ... 省略一些代碼
}
console.log(i)  // 5

//after
for(let i = 0; i < 5; i++) {
    // ... 省略一些代碼
}
console.log(i) // 報錯 i is not defined


// 第二個對比
// before
var funcs = [];
for(var i = 0; i < 10; i++) {
    funcs.push(() => {console.log(i)})
}
funcs.forEach((ele) => {
    ele()
})
// 打印 10次 10

// after
var funcs = [];
for(let i = 0; i < 10; i++) {
    funcs.push(() => {console.log(i)})
}
funcs.forEach((ele) => {
    ele()
})
// 打印 0 1 2 3 4 5 6 7 8 9

注意:有一點很重要,let 聲明在循環內部的行爲是標準中專門定義的,它不必定與 let 不提高特性有關。

循環中的const聲明
// for 循環會報錯
for (const i = 0; i < 1; i++) {
    console.log(i)
}
// 打印 0 ,而後報錯 Assignment to constant variable.

// for-in 和 for-of 不會報錯
var object = {
    a: true,
    b: true,
    c: true
};
for (const key in object) {
    // 不要在循環體內更改key的值,會報錯
    console.log(key)
}
// 打印 a b c

注意:const能夠應用在 for-in 和 for-of 循環中,是由於每次迭代不會修改已有綁定,而是會建立一個新綁定。

五、 塊級綁定最佳實踐的進化

ES6 早期

廣泛認爲默認使用let來替代var,對於寫保護的變量使用const

ES6 使用中

廣泛默認使用const,只有確實須要改變變量的值時使用let。由於大部分變量的值在初始化後不該再改變,而預料以外的變量值的改變是許多bug的源頭。這樣就能夠在某種程度上實現代碼的不可變,從而防止某些錯誤的發生。

六、 全局變量將逐步與頂層對象的屬性脫鉤

頂層對象,在瀏覽器環境指的是window對象,在Node指的是global對象。

爲了保持兼容性,var命令和function命令聲明的全局變量,依舊是頂層對象的屬性;

var a = 1;
window.a // 1

var 聲明的a,在右側 global 裏面

另外一方面規定,let命令、const命令、class命令聲明的全局變量,不屬於頂層對象的屬性。

圖片描述

上圖可見let 聲明的變量,並無在Window對象裏,而是一個新的Script對象。

擴展:若是須要在瀏覽器中跨frame或window訪問代碼,仍然能夠用var在全局對象下定義變量。

七、 塊級函數

從ECMAScript 6開始,在嚴格模式下,塊裏的函數做用域爲這個塊。ECMAScript 6以前不建議塊級函數在嚴格模式下使用。

'use strict';

function f() {
  return 1;
}

{
  function f() {
    return 2;
  }
}

f() === 1; // true

// f() === 2 在非嚴格模式下相等

注意:在非嚴格模式下不要用塊級函數,由於在非嚴格模式下,塊中函數的聲明表現奇怪,有兼容性風險

if (shouldDefineZero) {
   function zero() {     // DANGER: 兼容性風險
      console.log("This is zero.");
   }
}

ECMAScript 6中,若是shouldDefineZero是false,則永遠不會定義zero,由於這個塊不執行。這是新標準定義的。然而,這裏存在歷史遺留問題,不管這個塊是否執行,一些瀏覽器會定義zero。

在嚴格模式下,全部支持ECMAScript 6的瀏覽器以相同的方式處理:只有在shouldDefineZero爲true的狀況下定義zero,而且做用域只是這個塊內。

相關文章
相關標籤/搜索