owned this note
owned this note
Published
Linked with GitHub
---
tags: 分享
---
# JavaScript ES6 介紹
## 歷史介紹
* ECMAScript 6 (簡稱 ES6),是 JavaScript 語言新一代的標準,在 2015 年 6 月正式發佈。
* ES6 其實是一個泛指的名詞,泛指 ES5.1 版以後的新一代 JavaScript 語言標準,涵蓋了 ES2015, ES2016, ES2017 等等,ES2015 則是正式名稱,特指該年度發佈的語言標準,現在常聽到人家說的 ES6,一般是指 ES2015 標準。
* ES6 提出了很多新的語法,使得 JavaScript 變得更強大,更適合用來寫大型的應用程式!
* ES6 新增的則是一些寫法上的改變,讓寫法變得更精簡,以及新增了非同步專用的 Promise 、 JS 模組化必備的 ES6 Modules 、 Classes
以下是 ES6 新的特性:
## 功能介紹
### 1. Block Scope 塊級作用域 - let, const
在 ES6 之前,JavaScript 用 **var** 關鍵字來宣告一個變數,其作用範圍是 function scope,在 ES6 中引入了兩個新的語法 **let 和 const** 讓你可以宣告塊級作用範圍 (block scope) 的變數。
所謂的 block scope 就是變數的作用範圍只存在兩個大括號 { } 中。
> let
let 關鍵字用來宣告一個 block scope 變數。
* let 可以宣告只能在目前區塊、階段或表達式中作用的變數。
* 而 var 則是定義了一個全域變數,或是在整個 function 而不管該區塊範圍。
```javascript=
function varTest() {
var x = 1;
{
var x = 2; // 這裡的 x 與 function 區塊內部的 x 是一樣的,因此會影響 function 區塊內所有的 x
console.log(x); // 2
}
console.log(x); // 2
}
function letTest() {
let x = 1;
{
let x = 2; // 這裡的 x 與 function 區塊內部的 x 是不同的,只會作用在這層 block 區塊中
console.log(x); // 2
}
console.log(x); // 1
}
```
在上列例子裡的最前行 let 和 var 不同,let 並不會在全域物件中建立變數。舉例來說:
```javascript=
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined
```
> const 常數
const 關鍵字跟 let 類似,也可以用來宣告一個 block scope 變數,不同的是,const 宣告的變數其指向的值不能再被改變。
```javascript=
{
const A = 10;
// 會發生錯誤,常數值不能再被改變
// TypeError: Assignment to constant variable
A = 10;
// 陣列是一個有趣的例子
const ARR = [1, 2];
// 可以改變陣列裡的內容
// 因為 ARR 變數值沒有改變,還是指向同一個陣列
ARR.push(3);
// [1, 2, 3]
console.log(ARR);
// 錯誤,不能改常數值
// TypeError: Assignment to constant variable
ARR = 123;
// 但可以改變陣列裡面的內容
ARR[0] = 4;
// [4, 2, 3]
console.log(ARR);
}
```
### 2. JavaScript ES6 Arrow Functions 箭頭函數
ES6 允許我們用箭頭 => 來更方便簡短的定義一個函數,這種語法稱作 Arrow Functions。
Arrow Functions 由參數列 (...) 接著 => 和函數內容所組成。
```javascript=
// 原始樣貌
function () {
};
// ES6
= () => {
};
```
例1:
```javascript=
// 傳統標準的函數宣告語法
var multiply = function(a, b) {
return a * b;
};
// 使用 Arrow Functions 的語法
var multiply = (a, b) => a * b;
// 20
multiply(2, 10)
```
例2:
```javascript=
let numbers = [1, 2, 3];
// callback 用 Arrow Functions 的寫法更精簡
let doubles = numbers.map(num => {
return num * 2;
});
// [2, 4, 6]
console.log(doubles);
```
### 3. JavaScript ES6 Default Function Parameters
在 ES6 中,JavaScript 函數的參數終於可以有預設值了。
```javascript=
// 傳統寫法
function multiply(a, b) {
b = (typeof b !== 'undefined') ? b : 1;
return a * b;
}
multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
// ES6寫法
multiply = (a, b = 1) => {
return a * b;
}
multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5); // 5
```
### 4. JavaScript ES6 Spread/Rest Operator 運算子
ES6 引入了新的運算子 (operator) ... (三個點號) 來表示展開或其餘運算子。
> Spread Operator 展開運算子
Spread Operator 可以用在執行函數時的參數列上,它可以將一個陣列 (array) 展開,轉為多個逗點隔開的獨立參數:
範例:
```javascript=
// 例1
function foo(x, y, z) {
console.log(x, y, z);
}
var arr = [1, 2, 3];
// 輸出 1 2 3
// 等同於執行 foo(1, 2, 3)
foo(...arr);
// 例2
function foo2(a, b, c, d, e) {
console.log(a, b, c, d, e);
}
var arr2 = [3, 4];
// 輸出 1 2 3 4 5
// 等同於執行 foo(1, 2, 3, 4, 5)
foo(1, 2, ...arr2, 5);
// 例3
var parts = ['shoulders', 'knees'];
// 將 parts 展開在 lyrics 的元素中
var lyrics = ['head', ...parts, 'and', 'toes'];
// lyrics 的值會變成 ["head", "shoulders", "knees", "and", "toes"]
// 例4
var ary1 = [4, 5, 6];
var ary2 = [1, 2, 3];
// ary1 會變成 [1, 2, 3, 4, 5, 6]
ary1 = [...ary2, ...ary1];
```
### 5. JavaScript ES6 Object Literal Extensions 物件實字的擴展
ES6 的新語法讓 object literal 可以寫得更簡短清楚。
如果屬性名稱和變數名稱一樣,可以在物件裡面只使用變數,變數的名城也會被當作是屬性名稱,而變數的值會被當作屬性值。
用法:
```javascript=
var obj = {
foo,
bar
};
```
上面的語法同等於:
```javascript=
var obj = {
foo: foo,
bar: bar
};
```
> Computed property keys 計算得出的屬性名稱
ES6 允許使用表達式 (expression) 作為屬性的名稱,語法是將 expression 放在中括號 [ ] 裡面,透過 [ ] 的語法,我們的屬性名稱就可以放入變數,達到動態產生屬性名稱的效果。
```javascript=
var prefix = 'es6';
var obj = {
// 計算屬性
[prefix + ' is']: 'cool',
// 計算方法
[prefix + ' score']() {
console.log(100);
}
};
// 顯示 cool
console.log(obj['es6 is']);
// 顯示 100
obj['es6 score']();
```
### 6. JavaScript ES6 Octal/Binary Literals 八進位/二進位表示法
ES6 支援 octal literal 和 binary literal。
可以直接輸入下方兩種樣式
二進位表示法 0b 或 0B 表示。
八進位表示法0o 或 0O 表示。
```javascript=
var oValue = 0o10;
// 8
console.log(oValue);
var bValue = 0b10;
// 2
console.log(bValue);
```
### 7. JavaScript ES6 Array and Object Destructuring Assignment 陣列和物件的解構賦值
ES6 的 destructuring assignment,可以用來從陣列或物件中抽取 (destructuring) 值出來指定 (assignment) 給變數。
ES6以前 在給予值只能用指定的方式
```javascript=
var one = 'one';
var two = 'two';
var three = 'three';
```
現在 ES6的寫法
```javascript=
var foo = ["four", "five", "six"];
var [four, five, six] = foo;
// 從 array 中提取值,然後按照對應的位置,指定給相應的變數
// "four"
console.log(four);
// "five"
console.log(five);
// "six"
console.log(six);
```
只要結構一樣,就能取得對應的值
```javascript=
var obj = {
p: [
'Hello',
{
y: 'World'
}
]
};
var {p: [x, {y}]} = obj;
// "Hello"
console.log(x);
// "World"
console.log(y);
```
```javascript=
const obj = {
name : apple,
age : 20,
birthday : 2000/01/01
}
// 傳統寫法
const name = obj.name;
const age = obj.age;
const birthday = obj.birthday;
// "apple , 20 , 2000/01/01"
console.log(name,age,birthday);
// ES寫法 ,前提是要名稱一模一樣
const { name , age , birthday } = obj;
// "apple , 20 , 2000/01/01"
console.log(name,age,birthday);
```
### 8. JavaScript ES6 super Keyword
在 ES6 中新增的 super 關鍵字 (keyword),在物件的方法 (method) 中使用時,super 會指向父類別 (的 prototype),方便我們可以存取父類別中的。
只能用在ES6新的方法中,如果放在傳統的 function 會出錯。
// Uncaught SyntaxError: 'super' keyword unexpected here
```javascript=
var parent = {
foo() {
console.log('Hello from the Parent'); // 2
},
a: 'a of parent' // 4
}
var child = {
foo() {
console.log('Hello from the child'); // 1
super.foo();
console.log(this.a);
console.log(super.a)
},
a: 'a of child' // 3
}
Object.setPrototypeOf(child, parent);
child.foo();
```
接著會依序列出
```javascript=
Hello from the child
Hello from the Parent
a of child
a of parent
```
### 9. JavaScript ES6 Template Literals 字串樣版
ES6 引入了 Template Literals (字串樣版) 是增強版的字串表示法,Template Literals 讓你可以寫多行字串 (multi-line strings)、也可以在字串中插入變數或 JavaScript 表達式 (String/Expression interpolation)。
Template Literals 的語法是用兩個反引號 (back-tick) ` `` ` 標示,而在字串中可以使用 ${ } 語法來嵌入變數或 JavaScript 表達式。
```javascript=
// 傳統的寫法:
var str = 'string text line 1\n' +'string text line 2'
// Template Literals 新的寫法:
var str = `string text line 1
string text line 2`
```
> 嵌入變數或任何表達式 String/Expression Interpolation
傳統的寫法 都必須一直使用 + 跟''來組合物件
```javascript=
var a = 5;
var b = 10;
console.log('Fifteen is ' + (a + b) + ' and\nnot ' + (2 * a + b) + '.');
```
ES6的寫法直觀很多
```javascript=
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`);
```
### 10. JavaScript ES6 for...of 迴圈
在 ES6 之前,有幾種迴圈的寫法可以遍歷一個陣列:
1. for 迴圈
2. for...in 迴圈
3. forEach 方法
最一開始的for 迴圈寫起來過於冗長,所以ES5 使用forEach來簡化迴圈,但有個缺點是不能使用 break 來中斷迴圈,或用 return 直接返回迴圈最外層
ES6 新的 for...of 語法有什麼好處:
1. 更簡潔直觀的語法
2. 沒有 for...in 的缺點
3. 跟 forEach 不同的是 for...of 可以搭配 break, continue, return 語句
4. for...of 支持遍歷更多的集合類型,像是 string, Map, Set...
```javascript=
let number = [10, 20, 30];
for (let value of number) {
value += 1;
console.log(value);
}
// 依序輸出
// 11
// 21
// 31
```
### 11. JavaScript ES6 Map and WeakMap Object 物件
ES6 新增了 Map 和 WeakMap 數據結構。
Map
Map 有點像是 object (key-value pairs),兩者不同的地方在於 object 的 key 只能是字串 (string);而 Map 的 key 則可以是任何的資料型態!
另外 Map 中的資料是有序的,當你遍歷一個 Map 資料結構時,會依照 key-value pairs 先前寫入的順序 (insertion order)。
> 建立 Map 物件的語法:
```javascript=
// 建立一個空 Map
new Map()
// 建立一個 Map 並初始化
new Map(iterable)
```
使用範例
```javascript=
// 建立一個 Map 物件
var myMap = new Map();
var keyString = 'a string';
var keyObj = {};
var keyFunc = function() {};
// set() 用來新增 key-value pair
// key 不限字串,可以是任何的資料型態
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, 'value associated with keyObj');
myMap.set(keyFunc, 'value associated with keyFunc');
// get() 用來取得某個 key 的值
// 顯示 "value associated with 'a string'"
console.log( myMap.get(keyString) );
// 顯示 "value associated with keyObj"
console.log( myMap.get(keyObj) );
// 顯示 "value associated with keyFunc"
console.log( myMap.get(keyFunc) );
// 因為 keyString === 'a string'
// 顯示 "value associated with 'a string'"
console.log( myMap.get('a string') );
// 因為 because keyObj !== {}
// 顯示 undefined
console.log( myMap.get({}) );
// 因為 keyFunc !== function () {}
// 顯示 undefined
console.log( myMap.get(function() {}) );
```
### 12. JavaScript ES6 Set and WeakSet Object 物件
ES6 新增了 Set 和 WeakSet 數據結構。
Set
Set 有點像是陣列 (array),Set 中的元素 (element) 可以是任何資料型態,兩者不同的地方在於 Set 中所有的值都是唯一的 (unique values),不會有重複的值,當你存入重複值 (duplicate values) 會被忽略。
當你向 Set 中加入新元素時,Set 內部會用 === 來判斷是否有重複值,唯一的例外是 NaN 會被判斷作是重複的值,雖然 NaN !== NaN。
> Set.prototype.size
用來取得 Set 物件的大小,總共有幾個元素。
```javascript=
var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add('some text')
// 3
mySet.size;
```
> Set.prototype.add(value)
用來新增元素,add() 方法會返回 Set 本身。
```javascript=
var mySet = new Set();
mySet.add(1);
mySet.add(5)
mySet.add('some text');
// Set {1, 5, "some text"}
mySet;
```
> Set.prototype.has(value)
返回一個 boolean,判斷 Set 中有沒某個值。
```javascript=
var mySet = new Set();
mySet.add('foo');
// true
mySet.has('foo');
// false
mySet.has('bar');
```
### 13. JavaScript ES6 class 關鍵字
在 ES6 中,引入了 Class (類別) 這個新的概念,透過 class 這新的關鍵字,可以定義類別。
另外還引入了一些其他的新語法,來讓你更簡單直觀的用 JavaScript 寫 OOP (物件導向) 程式,但大多數語法只是語法糖 (syntactical sugar),並不是重新設計一套物件繼承模型 (object-oriented inheritance model),只是讓使用者更方便操作 JavaScript 既有的原型繼承模型 (prototype-based inheritance)。
可以用 class 語法定義一個類別:
```javascript=
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
```
也可以用extends 關鍵字用作類別繼承:
```javascript=
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
// 顯示 Mitzie barks.
d.speak();
```
### 14. JavaScript ES6 Promise Object 物件
Promise 是一種非同步 (asynchronous) 編程的解決方案,所謂的 Promise,簡單來說它是一個等待非同步操作完成的物件,當事件完成時,Promise 根據操作結果是成功、或者失敗,做相對應的處理動作。
一個 Promise 物件 (只) 會處於下面三種狀態之一:
pending - 初始狀態 (進行中)
fulfilled - 事件已完成
rejected - 事件已失敗
Promise 狀態的改變只有兩種可能:
從 pending 變成 fulfilled
從 pending 變成 rejected
範例
```javascript=
var promise = new Promise(function(resolve, reject) {
// ...
if (異步操作成功) {
resolve(value);
} else {
reject(error);
}
});
```