1. 程式人生 > >ES5、ES6、ES7電子教程

ES5、ES6、ES7電子教程

http://yanhaijing.com/es5/#about

 

ES5電子教程

中文版:http://yanhaijing.com/es5/#58
英文版:https://people-mozilla.org/~jorendorff/es5.1-final.html

ES6電子教程

中文版:http://es6.ruanyifeng.com/
英文版:http://www.ecma-international.org/ecma-262/6.0/#sec-type
ES6的瀏覽器相容性問題: https://segmentfault.com/a/1190000005128101

ES7電子教程

英文版:http://www.ecma-international.org/ecma-262/7.0/index.html

名詞解析

(1)連結: http://www.jb51.net/article/30719.htm

  • 變數提升
    1、查詢變數的順序是:活動物件-->全域性物件,一旦找到變數就停止查詢
    2、javascrip函式級作用域的影響,即函式會建立新的作用域
    3、變數提升,是把變數提升提到函式的頂部,只提升變數的宣告,賦值沒提升。
   //場景一
    var x = 1; //x儲存在全域性物件中
    console.log(x); // 1
    if (true) {
        var x = 2; //x儲存在活動物件中
        console.log(x); //2
    }
    console.log(x);// 2     
   //場景一
    var v='Hello World';
    (function(){
        alert(v); 
        var v='I love you';
        alert(v);
    })(); 
  //定義的三個變數
  (function(){
      var a='One';
      var b='Two';
      var c='Three';
  })();
  //實際上是這樣子的:
  (function(){
      var a,b,c;
      a='One';
      b='Two';
      c='Three';
  })();
  所以在定義js變數時候,需要把變數放在塊級作用域的頂端,先定義變數,以防出現錯誤。
  • 函式提升
    1、函式提升:就是把函式宣告提到作用域的頂部
    2、函式有兩種表達方式:函式宣告方式和函式表達方式
    3、只有函式宣告方式才能提升
  //函式宣告方式
    function myTest(){
        foo();
        function foo(){
            alert("我來自 foo");
        }
    }
    myTest(); 
 //函式表達方式
    function myTest(){
        foo();
        var foo =function foo(){
            alert("我來自 foo");
        }
    }
    myTest();
  • ** 暫時性死區**
    只要一進入當前作用域,所要使用的變數就已經存在,但是不可獲取,只有等到宣告變數的那一行程式碼出現,才可以獲取和使用該變數。
  • ** let與var區別**
    //不同之處
    1、let宣告的變數只在let所在的程式碼塊內有效
    2、var有變數提升,則宣告之前使用不會報錯;let沒有變數提升,宣告前使用會報錯
    3、let存在暫時性死區,只要塊級作用域記憶體在let命令,它所宣告的變數就“繫結”(binding)這個區域,不再受外部的影響
       var tmp = 123;
       if (true) {
            tmp = 'abc'; // ReferenceError 
            let tmp;
       }
 
   4、ES6規定,若區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡在宣告前就使用這些變數,均報錯。
   5、ES6規定暫時性死區和let、const語句不出現變數提升,主要是為了減少執行時錯誤。
   6、let不允許在相同作用域內,重複宣告同一個變數
  • ** 塊級作用域**
    ES5只有全域性作用域和函式作用域,沒有塊級作用域,這帶來很多不合理的場景
   1、避免由於變數提升,內層變數可能會覆蓋外層變數;
   2、避免用來計數的迴圈變數洩露為全域性變數;
   3、ES6允許塊級作用域的任意巢狀, 外層作用域無法讀取內層作用域的變數, 內層作用域可以定義外層作用域的同名變數;
 
       {{{{{let insane = 'Hello World'}}}}};
       {{{{ {let insane = 'Hello World'} console.log(insane); // 報錯}}}};
       {{{{ let insane = 'Hello World'; {let insane = 'Hello World'}}}}};
 
   4、塊級作用域可以替代立即執行的匿名函式的功能
   5、ES5(嚴格模式)規定,函式只能在頂層作用域和函式作用域之中宣告,不能在塊級作用域宣告
   6、ES6允許在塊級作用域之中宣告函式,只在大括號情況下可行,沒有大括號會報錯;函式宣告類似於var,存在函式提升
 
   注意:環境導致的行為差異太大,應該避免在塊級作用域內宣告函式。 若需要,也應該寫成函式表示式,而不是函式宣告語句
  • ** 頂層物件及其屬性**
    根據不同環境,頂層物件指:
    1、瀏覽器:window、self物件。有實體含義,即指代瀏覽器的視窗物件
    2、node: global物件
  ES5中,頂層物件的屬性與全域性變數等價,這是javascript語言設計的最大敗筆之一,原因:
  1、沒法在編譯時就報出變數未宣告的錯誤,只有執行時才能知道。因為全域性變數可能是頂層物件的屬性創造的,而屬性的創造是動態的。
  2、頂層物件到處可讀,不利於模組化程式設計
  3、人為創造全域性變數
 
  ES6中,對頂層物件及其屬性做了以下處理:
  1、保留var和function命令,其定義的全域性變數依然為頂層物件的屬性
  2、let、const、import、class四種命令定義的全域性變數不屬於頂層物件的屬性
 
  使用this物件獲取頂層物件,但具有一定侷限性:
  1、全域性環境中,this會返回頂層物件。
     但是,Node模組和ES6模組中,this返回的是當前模組。
  2、函式裡面的this,如果函式不是作為物件的方法執行,而是單純作為函式執行,this會指向頂層物件。
     但是,嚴格模式下,這時this會返回undefined。
  3、不管是嚴格模式,還是普通模式,new Function('return this')(),總是會返回全域性物件。
     但是,如果瀏覽器用了CSP(Content Security Policy,內容安全政策),那麼eval、new Function這些方法都可能無法使用
   在所有情況下,都取到頂層物件的方法:
    //方法一:
    (typeof window !== 'undefined'
       ? window
       : (typeof process === 'object' &&
          typeof require === 'function' &&
          typeof global === 'object')
         ? global
         : this);
 
    //方法二:
    var getGlobal = function () {
      if (typeof self !== 'undefined') { return self; }
      if (typeof window !== 'undefined') { return window; }
      if (typeof global !== 'undefined') { return global; }
      throw new Error('unable to locate global object');
    };   
  • 解構(Destructuring)賦值
    從陣列或物件中提取值,按照對應位置,對變數賦值
  解構賦值型別:
  1、陣列形式:資料結構具有Iterator介面.
        var:  var [v1, v2, ..., vN ] = array;
        let:   let [v1, v2, ..., vN ] = array;
        const:  const [v1, v2, ..., vN ] = array;
        Set結構:  let [x, y, z] = new Set(["a", "b", "c"]);
 
        function* fibs() {
          var a = 0;
          var b = 1;
          while (true) {
            yield a;
            [a, b] = [b, a + b];
          }
        }
        var [first, second, third, fourth, fifth, sixth] = fibs();    
       // fibs是一個Generator函式,原生具有Iterator介面。解構賦值會依次從這個介面獲取值                            
  2、物件形式:物件解構賦值與陣列解構賦值的區別:
      * 陣列的元素按次序排序,變數的值與位置有關;左邊變數在右邊的值可以不賦值
      * 物件的解構賦值,右邊的以欄位(變數名與變數值)形式存在,與左邊變數名的順序無關; 左邊的變數與右邊的變數一直,不可缺少
          var { foo, bar } = { foo: "aaa", bar: "bbb" };
          foo // "aaa"
          bar // "bbb"
 
          var { baz } = { foo: "aaa", bar: "bbb" };
          baz // undefined
  • 模式匹配
  “模式匹配”,只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。
 
    var [a,b,c]=[1,2,3]; //模式匹配法_變數的批量賦值
    console.log(b);
 
    //巢狀陣列解構
    let [foo,[[fa],fb],fc] = [1,[[2],3],4];
    console.log(fa)
 
    let [one,,three] = [1,2,"123"];
    console.log(three)
 
    let [start, ...d]=["999",2,"56","00"];
    console.log(start)
 
    let [x, y, ...z] = ['a'];
    console.log(x)
    console.log(y) 
    console.log(z)
 
    let [...arr] = [];
    console.log(arr) //陣列
    如果解構不成功,變數的值就等於undefined
    var [fo] = [];  // fo undefined
    var [bar, fo] = [1]; // fo undefined
 
    // 如果右邊不是陣列,或者嚴格地說,不是可遍歷的結構,那麼會報錯:
    let [foo] = 1;
    let [foo] = false;
    let [foo] = NaN;
    let [foo] = undefined;
    let [foo] = null;
    let [foo] = {};

ES5與ES6區別

  • 變數宣告方式
  ES5:2種方式。var, function
  ES6:6種方式。var, function,let, const, import, class
  • 預設值
    ES6允許變數指定預設值。
    var [foo = true] = [];
    foo // true
    [x, y = 'b'] = ['a']; // x='a', y='b'
    [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
    ES6內部使用嚴格相等運算子(===),判斷一個位置是否有值。所以,如果一個數組成員不嚴格等於undefined,預設值是不會生效的
    var [x = 1] = [undefined];
    x // 1
    var [x = 1] = [null];
    x // null
  上面程式碼中,如果一個數組成員是null,預設值就不會生效,因為null不嚴格等於undefined
  惰性求值: 如果預設值是一個表示式,那麼這個表示式是惰性求值的,即只有在用到的時候,才會求值
  預設值可以引用解構賦值的其他變數,但是該變數必須已經宣告,否則會報錯。



作者:lzyuan
連結:https://www.jianshu.com/p/e90c447aa645
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。