向ES6看齊,用更好的JavaScript(一)


眾所周知,JavaScript作為弱類型語言,一直是精華與糟粕共存,許多“詭異”的地方我們不得不接受並使用。其實ES6(又稱ECMAScript 2015)在2015年6月就已經正式發布了,其中提出的很多新的特性讓JavaScript更加完善和豐富,對於前端開發者可謂一大福音。

目前各大瀏覽器的最新版本對ES6的支持度也越來越高,大部分的特性都實現了( ES6 支持 )。另外現在也有很多的轉換器(如Babel),將ES6和ES7的代碼轉換為ES5的代碼,這就意味着我們現在就可以使用這些新特性應用到我們的項目中去。

本篇對ES6中的關於變量部分的新特性進行介紹,本系列傳送門:

1 利用let和const引入塊級作用域

以往JavaScript是不具有塊級作用域的,一個函數才能構成一個作用域,局部變量在整個函數內都是有定義的,舉個栗子

    for(var i = 0;i < 10;i++){
    }
    
    console.log(i);  //輸出10

最后在for循環之后,i變量僅用於for循環,但在卻被泄露成全局變量形成變量污染,這就是不合理的地方,通過ES6中定義的let關鍵字可以形成僅作用於該塊作用域的局部變量

    //ES6環境下
    for(let i = 0;i < 10;i++){
    }
    
    console.log(i);  //輸出ReferenceError(未定義)

利用Babel將這段ES6代碼轉換為ES5代碼后,實際上是對ES5的代碼對其原理進行模擬達到一致的效果,因此可以幫助我們的理解:

    //Babel轉換后
    for (var _i = 0; _i < 10; _i++) {
    }

    console.log(i); //輸出ReferenceError(未定義)

可以看到,對於let聲明的局部變量,如果外部有相同定義,會通過添加下划線將其轉換為另外的變量,表達意思就是let將該變量僅在該塊作用域內可用。

再舉個栗子:

    var a = [];
    for (var i = 0; i < 3; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[1](); //輸出3
    a[2](); //輸出3

上面的代碼的三次循環中i始終為同一個變量,值最后為3。a數組中的函數讀到的i也是這個值,因此都是輸出3,這跟我們想要的結果並不一致。而利用let這個新特性可以很好的解決這個問題:

    //ES6環境
    var a = [];
    for (let i = 0; i < 3; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[1](); //輸出1
    a[2](); //輸出2
    //Babel轉換后
    var a = [];
    var _loop = function _loop(i) {
        a[i] = function () {
            console.log(i);
        };
    };
    
    for (var i = 0; i < 3; i++) {
        _loop(i);
    }
    a[1](); //輸出1
    a[2](); //輸出2

這次轉換后稍微變得復雜了一些,實際上是新定義一個函數,將循環變量i作為參數傳進去,可以這樣理解ES6中代碼通過let將三次循環中的i固定於各自的塊作用域中,互不干擾。

另外關於let要注意的幾點:

    console.log(a);   //輸出ReferenceError(未定義),let聲明的變量不會變量提升,這也是規范我們的代碼先聲明后使用。
    let a = 3;    
    let a = 4;     //錯誤,let聲明的變量不能重復定義

總之,用let讓我們的代碼更加規范避免了很多問題,因此盡可能使用let代替var.

  • let類似const也能形成塊作用域,不同點在於const聲明的變量為常量,不可改變

舉個栗子:

    if(true){
        const MAX = 999;
        MAX = 3;  //報錯:"MAX" is read-only
    }
    console.log(MAX);//輸出ReferenceError(未定義)
    

可以看出const也形成塊級作用域,而且值不可改變,有一點要注意的是不能改變的是const類型變量存儲的東西,舉個栗子更好理解:

    const person = {};
    person.name = 'vicfeel';  //正確,person存儲的是指向該對象的地址,對象內容可以改變
    person = {};  //報錯:"person" is read-only,該地址不能改變

2 變量解析與賦值

以往多個變量的賦值我們使用如下的方式:

    var a = 1;
    var b = 2;
    var c = 3;
    
    var d = 4,e = 5,f = 5;

ES6中增加一種更便捷的多變量賦值方法:

    var [a,b,c] = [1,2,3];

系統會自動對數組內元素進行對應賦值,也就是說我們也可以用這種方式來進行變量的聲明:

    //ES6環境下
    var arr = [1,2,3];
    var [a,b,c] = arr;

我們用Babel看一下是如何模擬的:

    //Babel轉換后
    var _ref = [1, 2,3];
    var a = _ref[0];
    var b = _ref[1];
    var c = _ref[2];

可以看到是通過數組下標依次向后賦值,下面我對多種情況進行了賦值測試:

    {
        //數量不對應
        let [a,b,c] = [1,2];
        console.log(a);  //1
        console.log(b);  //2
        console.log(c);  //undefined
        //按照上面babel轉換的理解,c = _ref[2]不存在該要素因此c為undefined
    }
    {
        //多層數組
        let [a,[b,c],d] = [1,[2,3],4];
        console.log(a);  //1
        console.log(b);  //2
        console.log(c);  //3
        console.log(d);  //4
    }
    {
        //多層不對應
        let [a,[b,c],d] = [1,[2],3];
        console.log(a);  //1
        console.log(b);  //2
        console.log(c);  //undefined
        console.log(d);  //3
    }
    {
        //對應值非數組
        let [a,b,c] = 1;  //報錯
        let [a,b,c] = false;  //報錯,等號右邊必須為可遍歷對象
    }

了解映射的原理之后,一個很好的應用場景就是交換數值,現在可以這樣簡單的實現:

    //ES6環境下
    let [x,y] = [0,1];
    [x,y] = [y,x]; 
  • 除此之外,ES6還在映射賦值中加入了默認值
//ES6環境下
let [a, b = 2,c] = [1]; //y無對應值時,默認值則為2
console.log(a);  //1
console.log(b);  //2
console.log(c);  //undefined

看一下ES5的模擬

//Babel轉換后
var _ref = [1];
var a = _ref[0];
var _ref$ = _ref[1];
var b = _ref$ === undefined ? 2 : _ref$; //通過‘===’嚴格等於判斷是否為undefined,是的話采用默認值
var c = _ref[2];   //所以是undefined
  • 針對對象的映射賦值

直接看栗子:

    //ES6環境下
    var { oA, oB } = { oA: "a", oB: "b" };
    console.log(oA); //"a"
    console.log(oB); //"b"

看一下ES5的模擬

    //Babel轉換后
    var _oA$oB = { oA: "aaa", oB: "bbb" };
    var oA = _oA$oB.oA;   //原來是通過同名屬性進行對應
    var oB = _oA$oB.oB;
    
    console.log(oA);
    console.log(oB);

了解了對應的原理之后,我們再做一下其它情況的測試:

    {
        //順序改變
        var { oA, oB } = { oB: "a", oA: "b" };
        console.log(oA); //"b"
        console.log(oB); //"a"
    }
    {
        //數量不對應
        var { oA, oB } = { oA: "a"};
        console.log(oA); //"a"
        console.log(oB); //undefined,等號右邊對象找不到oB屬性
    }

掌握這種方法,可以簡化很多之前操作,如獲取一個對象的某些屬性,可以通過以下方式:

    //ES6環境下
    var person = {
       name:'Vicfeel',
       age:'23',
       sex:'Male'
    }
    
    let {name,age,sex} = person;
    
    console.log(name);//Vicfeel
    console.log(age); //23
    console.log(sex); //Male

參考Reference
http://www.ecma-international.org/ecma-262/6.0/index.html
http://es6.ruanyifeng.com/
http://www.cnblogs.com/Wayou/p/es6_new_features.html
http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html

博文作者:vicfeel
博文出處:http://www.cnblogs.com/vicfeel
本文版權歸作者和博客園共有,歡迎轉載,但須保留此段聲明,並給出原文鏈接,謝謝合作!
如果閱讀了本文章,覺得有幫助,您可以為我的博文點擊“推薦一下”!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM