1. 程式人生 > >過一遍ES6知識點(一)

過一遍ES6知識點(一)

本文具體內容:

  1. let的相關用法以及所需要注意的問題
  2. const的相關用法
  3. 宣告變數的6中方式
  4. 加深對塊級作用域的理解
  5. 頂層物件(如何在不同環境中獲取頂層物件)

let 和 const 命令

let 的使用

  • let 用來宣告變數,只在let命令所在的程式碼塊中有效。【程式碼塊:使用花括號包住的內容稱為程式碼塊{}】

    利用let只在當前程式碼塊中有效的特性 解決 for 迴圈中的問題:
    這裡寫圖片描述
    這裡寫圖片描述
    總結:
    - var宣告的變數在全域性範圍內都有效,全域性變數只有一個i,所以每一次的迴圈,變數i的值度會發生改變。在陣列a的函式內部的變數i指向的就是全域性的i。所以無論執行陣列a的哪一個成員最終所打印出的i均為10
    - let 宣告的變數在塊級作用域內有效,即在迴圈中,當前的i只在本輪迴圈有效。所以每一輪迴圈都是全新的變數i。
    問題:


    每一輪的i重新宣告,那麼怎麼知道上一輪迴圈的值,從而計算出本輪迴圈的值?
    解答:JavaScript引擎內部會記住上一輪迴圈的值,初始化本輪的變數i時,就在上一輪的迴圈基礎上進行計算
    注意:

    這裡寫圖片描述
    for迴圈有一個特別之處:設定迴圈變數的部分是一個父作用域,而迴圈體內部是一個單獨的子作用域

  • let不存在變數提升
    變數提升: 即變數在宣告之前可以使用,值為undefined
    若使用let來宣告,在宣告之前使用變數將會報錯
    這裡寫圖片描述
  • let =>暫時性死區
    即只要在這個{塊級作用域}中使用let來定義變數,則所宣告的變數將“繫結”這個區域,不會受外部(全域性變數)的影響。
    【全域性變數的名稱與塊級作用域的名稱一致時,則全域性變數將不會在塊級作用域中起作用。】
    這裡寫圖片描述


    let變數宣告之前的部分均屬於let變數的死區,只要在之前使用了let變數均會報錯
    這裡寫圖片描述
    隱蔽的死區

  • 下圖程式碼中,呼叫bar函式之所以報錯(某些實現可能不報錯),是因為引數x預設值等於另一個引數y,而此時y還沒有宣告,屬於”死區“。如果y的預設值是x,就不會報錯,因為此時x已經聲明瞭。

    這裡寫圖片描述

  • let宣告x變數時,還沒有宣告完成之前,使用變數將會報錯
    這裡寫圖片描述

  • 不允許重複宣告
    不允許在相同作用域內重複宣告同一個變數【不能在函式內部重新宣告引數】
    這裡寫圖片描述
    這裡寫圖片描述

const的使用
1.基本規則

  • 宣告只讀常量
  • 聲明後不可修改
  • 一旦宣告,必須馬上初始化
  • 若只宣告不初始化將報錯
  • 只在宣告所在的塊級作用域內有效
  • 宣告的常量不提升,存在暫時性死區,只能在宣告的位置後面使用
  • const宣告的常量,與let一樣不可重複宣告(不管使用var、let、還是const宣告均不可)

2.本質

  • 並不是值不可變動,而是變數指向的記憶體地址所儲存的資料不得改動
  • 對於簡單型別的資料(數值、字串、布林值),值儲存在變數所指向的記憶體地址,因此等同於變數。
  • 對於複合型別的資料(物件與陣列),變數指向的記憶體地址,儲存的只是一個指向實際資料的指標,const只能保證指標是固定的,即總指向另一個固定的地址,並不能控制其地址中所存的資料。所以將物件宣告為常量時需要小心。
    這裡寫圖片描述
    這裡寫圖片描述
  • 將物件凍結,使得新增新屬性將不起作用,在嚴格模式下將會報錯
    這裡寫圖片描述
  • 將物件屬性也凍結,即將物件徹底凍結
    這裡寫圖片描述

宣告變數的六種方式

es5:
- var
- function
es6:
- let
- const
- import
- class

為什麼出現塊級作用域

  1. 內層變數可能覆蓋外層變數
    這裡寫圖片描述
    呼叫f()函式之後打印出的結果為undefined。這是由於var宣告的變數存在變數提升,導致內層的tmp覆蓋了外層的tmp變數。列印結果時內層變數並沒有賦值
  2. 用來計數的迴圈變數洩露為全域性變數
    這裡寫圖片描述
    變數i只用來控制迴圈,但是迴圈結束之後,i變數並沒有消失,而是洩露成了全域性變數

ES6的塊級作用域

  1. 兩個程式碼塊中的同名變數不相互影響
  2. 外層作用域無法讀取內層作用域的變數
  3. 內層作用域可以定義外層作用域的同名變數,但二者不相互影響

塊級作用域與函式宣告

  1. 在ES6中,允許在塊級作用域之中宣告函式
  2. 塊級作用域中,函式宣告語句在塊級作用域之外不可引用
  3. 在瀏覽器ES6的環境中,塊級作用域內宣告的函式,行為類似於var宣告的變數,會提升到所在的塊級作用域的頭部。但是在其他環境中還是將塊級作用域的函式聲明當做let來處理
  4. ES6允許在塊級作用域中宣告函式,條件是使用{}
    這裡寫圖片描述
    程式碼示例:
    這裡寫圖片描述
    上圖程式碼在瀏覽器ES6環境中,會報錯。其實際執行的是下面的程式碼:
    這裡寫圖片描述
    注意:避免在塊級作用域內宣告函式,若需要,可以寫成函式表示式的形式

頂層物件模型

  1. 頂層物件概念:
    瀏覽器中指window物件
    node環境中指global物件
    在ES5,頂層物件的屬性與全域性變數是等價
    這裡寫圖片描述
 *瀏覽器中,頂層物件是window,但Node和Web Worker是沒有window的
 *瀏覽器和Web Worker裡面,self也指向頂層物件,但是Node沒有self
 *Node裡面,頂層物件是global,但其他環境都不支援

同一段程式碼為了可以在各種環境都能取到頂層物件,目前一般使用this變數,但是具有侷限性

*全域性環境中,this會返回頂層物件,但是在Node模組和ES6模組中,this返回的是當前模組
*函式裡面的this,如果函式不是作為物件的方法執行,而是單純作為函式執行,this會指向頂層物件,但是嚴格模式下,this此時返回的是undefined
*無論是嚴格模式還是普通模式,new Function(‘return this’)(),總是會返回全域性物件。但是如果瀏覽器使用CSP(Content Security Policy,內容安全策略),那麼evalnew Function這些方法都可能無法使用

勉強可以使用下圖中的方式,在所有情況下,都取到頂層物件:
這裡寫圖片描述
11. 全域性變數與頂層物件等價引發的問題
* 沒有辦法在編譯時報出未宣告的錯誤,只有執行時才知道是否未宣告。
(全域性變數可能是由頂層物件的屬性創造的,而屬性的創造是動態的)
* 在不知覺中我們可能就建立了全域性變數
* 頂層物件的屬性可以到處讀寫,不利於模組化程式設計
window物件有實體含義,指的是瀏覽器的視窗物件,頂層物件是一個有實體含義的物件,是不合適的
12. ES6針對這一現象所做的改變
*保持相容性:var和function命令宣告的全域性變數依舊是頂層物件的屬性
*let、const、class所宣告的全域性變數,不屬於頂層物件的屬性。也就是說,ES6開始,全域性變數將逐步與頂層物件的屬性脫鉤
例如:
這裡寫圖片描述

global物件

  • 目前有一個提案,在語言標準的層面,引入global作為頂層物件。也就是說,在所有環境下,global都是存在的,都可以從它拿到頂層物件。
  • 墊片庫system.global模擬了這個提案,可以在所有環境拿到global
    這裡寫圖片描述