ES6標準入門 第3版 讀書筆記1

目錄2:let 和 const 命令

  1. var 存在變量提升。爲了糾正這個現象,let,const 聲明的變量會產生“暫時性死區”
    暫時性死區的本質:只要進入當前作用域,所使用的變量就已經存在,但是不可獲取。只有等到聲明變量的那一行代碼出現,纔可以獲取和使用該變量。
  2. let const 不允許在相同作用域內重複聲明一個變量。var 可以!
  3. ES5規定,函數只能在頂層作用域和函數作用域內聲明,不能在塊級作用域聲明。 但爲了兼容以前的舊代碼,瀏覽器並沒有遵循這個規定,還是支持在塊級作用域內聲明函數,函數會被提升到頂部;
  4. ES6引入了塊級作用域,明確可以在塊級作用域中聲明函數。ES6規定,塊級作用域之中,函數聲明語句的行爲類似於let,在塊級作用域之外不可引用。但是,實際上,爲了減輕因此產生的不兼容問題,瀏覽器可以不遵守上面的規定,有自己的行爲方式(只對ES6瀏覽器有效):
    • 允許在塊級作用域內聲明函數。
    • 函數聲明類似於var,即會提升到全局作用域或函數作用域的頭部。
    • 同時,函數聲明還會提升到所在的塊級作用域的頭部。
    // 瀏覽器的 ES6 環境
    function f() { console.log('I am outside!'); }
    
    (function () {
      if (false) {
        // 重複聲明一次函數f
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    
    實際運行如下:
    // 瀏覽器的 ES6 環境
    function f() { console.log('I am outside!'); }
    (function () {
      var f = undefined;
      if (false) {
        function f() { console.log('I am inside!'); }
      }
    
      f();
    }());
    // Uncaught TypeError: f is not a function
    
    注意:
    • 考慮到環境導致的行爲差異太大,應該避免在塊級作用域內聲明函數。如果確實需要,應寫成函數表達式。

    • ES6的塊級作用域必須有大括號

      // 第一種寫法,報錯 沒有大括號,所以不存在塊級作用域,而let只能出現在當前作用域的頂層
      if (true) let x = 1;
      
      // 第二種寫法,不報錯
      if (true) {
        let x = 1;
      }
      
    • 函數聲明也是如此,嚴格模式下,函數只能聲明在當前作用域的頂層。

  5. const 實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。如果想將對象凍結,應該使用Object.freeze()方法。
    const foo = Object.freeze({});
    
    // 常規模式時,下面一行不起作用;
    // 嚴格模式時,該行會報錯
    foo.prop = 123;
    
    除了將對象本身凍結,對象的屬性也應該凍結:
    var constantize = (obj) => {
      Object.freeze(obj);
      Object.keys(obj).forEach( (key, i) => {
        if ( typeof obj[key] === 'object' ) {
          constantize( obj[key] );
        }
      });
    };
    
  6. ES5有兩種聲明變量的方法:varfunction。ES6除了letconst,還有importclass
  7. 頂層對象:在瀏覽器中指window對象,在Node中指global對象。ES5中,頂層對象的屬性和全局變量是等價的。但是在ES6中,var function聲明的全局變量依舊是頂層對象的屬性,而 let const class聲明的全局變量不屬於頂層對象的屬性。
var a = 1;
// 如果在 Node 的 REPL 環境,可以寫成 global.a
// 或者採用通用方法,寫成 this.a
window.a // 1

let b = 1;
window.b // undefined
  1. 頂層對象在各種實現裏面是不統一的:
    • 瀏覽器,頂層對象獲取:windowselfframes, 全局環境中的this , 函數不作爲對象的方法運行,而是單純作爲函數運行,this會指向頂層對象,但是嚴格模式下,返回undefined
    • Web Worker,頂層對象獲取:self
    • Node,頂層對象獲取:global
    • ES2020引入了globalThis作爲頂層對象,任何環境下都可以通過它拿到頂層對象;

目錄3:變量的解構賦值

  1. ES6內部使用嚴格相等運算符===,來判斷一個位置是否有值。只有嚴格等於undefined,默認值纔會生效。
  2. 對象的解構與數組的解構有一個重要的不同。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性名同名,才能取到正確的值;
  3. 解構失敗等於undefined
  4. 對象解構,如果變量名與屬性名不一致,必須寫成下面這樣:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
  1. 對象的解構賦值可以取到繼承的屬性
  2. 注意點:
    • 將一個已經聲明的變量用於解構賦值,需要非常小心:
    // 錯誤的寫法
    let x;
    {x} = {x: 1};
    // SyntaxError: syntax error
    
    // 正確的寫法
    let x;
    ({x} = {x: 1});
    
    • 解構賦值允許等號左邊的模式之中,不放置任何變量名:
    ({} = [true, false]);
    ({} = 'abc');
    ({} = []);
    
    • 數組本質是特殊的對象,因此可以對數組進行對象屬性的解構:
    let arr = [1, 2, 3];
    let {0 : first, [arr.length - 1] : last} = arr;
    first // 1
    last // 3
    
  3. 字符串也可以解構賦值,如下:字符串會被轉換爲一個類似數組的對象:
    類似數組的對象都有一個length屬性,因此還可以對這個屬性解構賦值
    const [a, b, c, d, e] = 'hello';
    a // "h"
    b // "e"
    c // "l"
    d // "l"
    e // "o"
    
    let {length : len} = 'hello';
    len // 5
    
  4. 解構賦值的規則是:只要等號右邊的值不是對象或數組,就先將其轉爲對象。由於,undefinednull無法轉爲對象,所以對它們進行解構賦值,都會報錯。
  5. 解構賦值中,不能使用圓括號:變量聲明語句,函數參數,賦值語句的模式; 可以使用圓括號:賦值語句的非模式部分;
    10.變量解構賦值的用途:
    • 交換變量的值
    • 從函數返回多個值
    • 函數參數的定義
    • 提取JSON數據
    • 函數參數的默認值
    • 遍歷Map結構
    • 輸入模塊的指定方法

目錄四:字符串的擴展

  1. 字符的Unicode表示法;ES6加強了對Unicode的支持,允許採用\uxxxx形式表示一個字符,其中xxxx表示字符的Unicode碼點;
    '\z' === 'z'  // true
    '\172' === 'z' // true
    '\x7A' === 'z' // true
    '\u007A' === 'z' // true
    '\u{7A}' === 'z' // true
    
  2. ES6爲字符串添加了遍歷器接口iterator,使得字符串可以被for ... of循環遍歷
    傳統的for循環無法識別這樣的碼點
    let text = String.fromCodePoint(0x20BB7);
    //for循環會認爲它包含兩個字符(都不可打印)
    for (let i = 0; i < text.length; i++) {
      console.log(text[i]);
    }
    // " "
    // " "
    
    for (let i of text) {
      console.log(i);
    }
    // "𠮷"
    
  3. 根據標準,JSON數據必須是UTF-8編碼。但是JSON.stringify()方法有可能返回不符合UTF-8標準的字符串。UTF-8標準規定,0xD8000xDFFF之間的碼點,不能單獨使用,必須配對使用;比如,\uD834\uDF06是兩個碼點,但是必須放在一起配對使用,代表字符𝌆。這是爲了表示碼點大於0xFFFF的字符的一種變通方法。
    JSON.stringify()的問題在於,它可能返回0xD8000xDFFF之間的單個碼點。爲了確保返回的是合法的UTF-8字符,ES2019改變了JSON.stringify()的行爲。如果遇到0xD8000xDFFF之間的單個碼點,或者不存在的配對形式,它會返回轉義字符串,留給應用自己決定下一步的處理。·
JSON.stringify('\u{D834}') // ""\\uD834""
JSON.stringify('\uDF06\uD834') // ""\\udf06\\ud834""

目錄5:字符串的新增方法

  1. ES5提供String.fromCharCode()方法,用於從Unicode碼點返回對應字符,但是這個方法不能識別碼點大於0xFFFF的字符;
  2. ES6提供了String.fromCodePoint()方法,可識別大於0xFFFF的字符;
  3. 傳統上,JS只有indexOf方法,用來確定一個字符串是否包含在另一個字符串中。ES6又提供了三種新的方法:
    • includes():返回布爾值,表示是否找到了參數字符串。
    • startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
    • endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
  4. 實例方法:normalize() includes() startsWith() endsWith()
  • repeat() :返回一個新的字符串,將原字符串重複n次
  • ES2017引入了字符串補全長度的功能;如果某個字符串不夠指定長度,會在頭部或尾部補全;padStart()用於頭部補全,padEnd()用於尾部補全;
    第一個參數是字符串補全生效的最大長度,第二個參數是用來補全的字符串。
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'
    
  • ES2019對字符串實例新增了trimStart()trimEnd()方法;它們的行爲與trim()一致,trimStart()消除字符串頭部的空格,trimEnd()消除尾部的空格。它們返回的都是新字符串,不會修改原始字符串。
    瀏覽器還部署了額外的兩個方法,trimLeft()trimStart()的別名,trimRight()trimEnd()的別名。
  • matchAll()方法返回一個正則表達式在當前字符串的所有匹配;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章