ES6語法


1.let

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

新建index.html,文件內容為

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

從console中可以打印出a的值

在ES6中,使用let聲明a的值,然后再次打印a的值,會報錯

<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>

刷新瀏覽器后可以看到,拋出的異常又不一樣了

因為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方法。


免責聲明!

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



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