ES6語法

1.let

ES6新增了let命令,用來聲明變量。它的用法相似於var,可是所聲明的變量只在let命令所在的代碼塊內有效javascript

新建index.html,文件內容爲html

<script type="text/javascript">
    {
        var a = 12;
    }
    console.log(a);
</script>

從console中能夠打印出a的值java

在ES6中,使用let聲明a的值,而後再次打印a的值,會報錯python

<script type="text/javascript">
    {
        let a = 12;
    }
    console.log(a);
</script>

報錯以下所示,程序員

上面兩個例子中,分別用let和var聲明瞭兩個變量。而後在代碼塊以外調用這兩個變量,結果let聲明的變量報錯,var聲明的變量返回了正確的值。這代表,let聲明的變量只在它所在的代碼塊有效編程

修改上面的代碼:瀏覽器

<script type="text/javascript">
    {
        var a = 12;
        var a = 20;
    }
    console.log(a);
</script>

結果以下函數

一樣的把上面的var改成let,學習

<script type="text/javascript">
    {
        let a = 12;
        let a = 20;
    }
    console.log(a);
</script>

刷新瀏覽器後能夠看到,拋出的異常又不同了this

由於let聲明的變量是塊級做用域,不能重複聲明

再次修改上面的代碼

<script type="text/javascript">
    var a = [];
    for(var i=0;i <10;i++){
        a[i] = function () {
            console.log(i);
        };
    }
    a[6]();
</script>

刷新瀏覽器,獲得的結果爲:

修改代碼,把var改成let

<script type="text/javascript">
    var a = [];
    for(let i=0;i <10;i++){
        a[i] = function () {
            console.log(i);
        };
    }
    a[6]();
</script>

再次刷新瀏覽器,獲得的結果爲:

上面代碼中,變量i是let聲明的,當前的i只在本輪循環有效,因此每一次循環的i其實都是一個新的變量,因此最後輸出的是6。

若是每一輪循環的變量i都是從新聲明的,那它怎麼知道上一輪循環的值,從而計算出本輪循環的值?這是由於 JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算

修改代碼

<script type="text/javascript">
    console.log(foo);
    var foo = 2;
</script>

刷新瀏覽器後,獲得的結果爲

一樣的,把var改成let,又會出現異常

var命令會發生」變量提高「現象,即變量能夠在聲明以前使用,值爲undefined。按照通常的邏輯,變量應該在聲明語句以後纔可使用。

爲了糾正這種現象,let命令改變了語法行爲,它所聲明的變量必定要在聲明後使用,不然報錯。

上面代碼中,變量foo用var命令聲明,會發生變量提高,即腳本開始運行時,變量foo已經存在了,可是沒有值,因此會輸出undefined。變量bar用let命令聲明,不會發生變量提高。

這表示在聲明它以前,變量bar是不存在的,這時若是用到它,就會拋出一個錯誤。

ES5 只有全局做用域和函數做用域,沒有塊級做用域,這帶來不少不合理的場景。

1.1 內層變量可能會覆蓋外層變量。

<script type="text/javascript">
    var tmp = new Date();
    console.log(tmp)
    function f() {
        console.log(tmp);
        if(false){
            var tmp = "hello world"
        }
    }
    f();
</script>

程序執行結果

上面代碼的原意是,if代碼塊的外部使用外層的tmp變量,內部使用內層的tmp變量。可是,函數f執行後,輸出結果爲undefined,緣由在於變量提高,致使內層的tmp變量覆蓋了外層的tmp變量。

1.2 用來計數的循環變量泄露爲全局變量。

<script type="text/javascript">
    var str = "hello";
    for(var i=0;i < str.length;i ++){
        console.log(str[i])
    }
    console.log(i)
</script>

執行結果:

2.模板字符串

傳統的JavaScript語言,輸出很長的信息時,一般都是使用"+"號進行拼接的。

這種方法至關繁瑣不方便,ES6引入了模板字符串解決這個問題

模板字符串(template string)是加強版的字符串,用反引號(`)標識。它能夠看成普通字符串使用,也能夠用來定義多行字符串,或者在字符串中嵌入變量

上面代碼中的模板字符串,都是用反引號表示。若是在模板字符串中須要使用反引號,則前面要用反斜槓轉義。

執行結果:

3.箭頭函數

ES6容許使用"箭頭"(=>)定義函數

var f = a => a
等同於
var f = function(a){
    return a;
}

若是箭頭函數不須要參數或須要多個參數,就使用括號表明參數部分

//無參函數
var f = () => 5;
等同於
var f = function(){return 5};

//多個形參的函數
var f = (num1,num2) => num1 + num2
等同於
var f = function(num1,num2){
    return num1 + num2;
}

使用箭頭函數須要注意的點:

3.1 函數體內的this對象,就是定義時全部的對象,而不是使用時所在的對象

代碼:

<script type="text/javascript">
    var animal = {
        name:"小狗",
        age:3,
        fav:function () {
            // this是使用時定義的對象
            console.log(this);
            console.log(this.name);
        }
    };
    animal.fav();
</script>

執行結果:

使用箭頭函數定義上面的函數

<script type="text/javascript">
    var animal = {
        name:"小狗",
        age:3,
        fav: ()=>{
            // this指向定義時所在的對象(window)
            console.log(this);
            console.log(this.name);
        }
    };
    animal.fav();
</script>

執行結果:

3.2 箭頭函數內部不可使用arguments對象,該對象在函數體內不存在

再次修改上面的代碼,打印函數傳遞的參數arguments

<script type="text/javascript">
    var animal = {
        name:"小狗",
        age:3,
        fav:function () {
            // 沒有使用箭頭函數,可使用arguments獲取傳遞的參數
            console.log(arguments);
            console.log(this.name);
        }
    };
    animal.fav(2,3,4);
</script>

執行結果:

使用箭頭函數定義上面的fav函數,再次打印函數傳遞的參數arguments

<script type="text/javascript">
    var animal = {
        name:"小狗",
        age:3,
        fav: () => {
            // 使用箭頭函數時,arguments沒法使用
            console.log(arguments);
            console.log(this.name);
        }
    };
    animal.fav(2,3,4);
</script>

執行結果

4. 對象的單體模式

爲了解決箭頭函數this指向的問題 推出來一種寫法 對象的單體模式

程序執行結果:

5. 面向對象

5.1 構造函數的方式建立對象

<script type="text/javascript">
    function Animal(name, age) {
        this.name = name;
        this.age = age;
    }
    Animal.prototype.showName = function () {
        console.log(this.name)
    }
    var dog = new Animal("dog", 2);
    console.log(dog.name);
    console.log(dog.age);
</script>

上面這種寫法跟傳統的面嚮對象語言(好比 Java 和 python)差別很大,很容易讓新學習這門語言的程序員感到困惑。

ES6 提供了更接近傳統語言的寫法,引入了 Class(類)這個概念,做爲對象的模板。

經過class關鍵字,能夠定義類。ES6 的class能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。

5.2 class建立對象

修改上面的代碼,用class建立對象

<script type="text/javascript">
    class Animal {
        // 相似於python中的__init__方法
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }

        showName() {
            console.log(this.name);
        }
    }
    var d = new Animal("dog", 3);
    d.showName();
</script>

程序執行結果

上面代碼定義了一個「類」,能夠看到裏面有一個constructor方法,這就是構造方法,而this關鍵字則表明實例對象。

也就是說,ES5 的構造函數Animal,對應 ES6 的Animal類的構造方法。

Animal類除了構造方法,還定義了一個showName方法。注意,定義"類"的方法的時候,前面不須要加上function這個關鍵字,直接把函數定義放進去了就能夠了。另外,方法之間不須要逗號分隔,加了會報錯。

上面代碼表示,類自己就指向了類的構造函數。

使用的時候,也是直接對類使用new命令,跟構造函數的用法徹底一致。

5.3 constructor方法

constructor方法是類的默認方法,經過new命令生成對象實例時,自動調用該方法。

一個類必須有constructor方法,若是沒有顯式定義,一個空的constructor方法會被默認添加。

class Animal {
}

// 等同於
class Animal {
  constructor() {}
}

上面代碼中,定義了一個空的類Point,JavaScript 引擎會自動爲它添加一個空的constructor方法。

相關文章
相關標籤/搜索