覺得官方文件的說明太冗長了嗎?
這裡是用小編的理解來說明 ES6 到底新增了哪些方便好用的功能
以這篇文章當作前言,再搭配官方的文件,效果會更好喔!

新舊語法比較:http://es6-features.org/

Constant - 常數

1
const PI = 3.141593

Block-scoped variable - 用 let 宣告變數

1
2
3
4
for (let i = 0; i < 1; i++) {
console.log(i); // 0
}
console.log(i); // i is not defined
1
2
3
4
for (var j = 0; j < 1; j++) {
console.log(j); // 0
}
console.log(j); // 1

const & let 的共通點

  • 要在使用前宣告
  • 不能重複宣告

★ const 就是不能改值的 let ★

Block-scoped function

1
2
3
(function () {
// codes here
})();

以前要用下面的 code 把要執行的程式包起來,現在只需要大括號

1
2
3
4
5
6
7
8
9
{
function foo () { return 1 }
foo() === 1
{
function foo () { return 2 }
foo() === 2
}
foo() === 1
}

Arrow functions - 用箭頭簡化匿名函數

1
plus_numbers = numbers.map(v => v + 1);

以前要這樣寫

1
2
3
plus_numbers = numbers.map( function (v) {
return v + 1;
});

且可以使用 this 來取得當前的 object

1
2
3
4
this.nums.forEach((v) => {
if (v % 5 === 0)
this.fives.push(v)
})

參數現在可以用預設值了!!!


新的運算子:”…”

功能一:Rest Parameter,取剩下的參數

1
2
3
4
5
6
function remove_first(first, ...arr_others) {
return arr_others;
}
let result = remove_first(1, 2, 3, 4);
result === [2, 3, 4];

功能二:Spread Operator,將陣列或字串打散

1
2
3
4
5
6
7
8
let params = [ "hello", true, 7 ];
let other = [ 1, 2, ...params ]; // [ 1, 2, "hello", true, 7 ]
let str = "foo"
let chars = [ ...str ] // [ "f", "o", "o" ]
let numbers = [1, 2, 3];
let copyed_array = [...numbers]; // 也可用於複製 array

Template - 字串中帶入變數(必須使用`)

1
2
let username = 'Stream';
console.log(`Hello ${username}.`); // Hello Stream.

轉換二進位與八進位的數字

在開頭使用 0b 或 0o

1
2
0b111110111 === 503
0o767 === 503

正規式

新增 y 選項(類似 g,但會從剩下的字串的第一個字開始比對)

1
2
3
4
5
6
7
8
9
let s = 'aaa_aa_a';
let r1 = /a+/g;
let r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null,因剩下的字串為'_aa_a',第一個字就不符合了

物件

###簡化 assign value 的方式

1
2
3
let x = 1;
let y = 2;
let obj = {x, y}; // {x:1, y:2}

object 的 key 可以是運算式

1
2
3
4
let obj = {
foo: "bar",
[ "baz" + quux() ]: 42
}

簡化 object 內 function 的宣告

1
2
3
obj = {
foo (a, b) {}
}

舊的寫法如下

1
2
3
obj = {
foo: function (a, b) {}
};

Destructing Assignment - 解構賦值

1
2
3
let list = [ 1, 2, 3 ];
let [ a, , b ] = list; // a === 1, b === 3
[ b, a ] = [ a, b ]; // 交換 a 和 b 的值

Module - import & export

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// lib/math.js
export function sum (x, y) { return x + y }
export var pi = 3.141593
// someApp.js
import * as math from "lib/math" // import 進來是個 object,並取名為 math
console.log("2π = " + math.sum(math.pi, math.pi))
// otherApp.js
import { sum, pi } from "lib/math"
console.log("2π = " + sum(pi, pi))
// lib/mathplusplus.js
export * from "lib/math"
export var e = 2.71828182846
export default (x) => Math.exp(x) // 可以 export 一個帶有 default 字眼的函數或變數
// someApp.js
import exp, { pi, e } from "lib/mathplusplus"
// exp 不在{}內,被 assign 成上面 export default 的函數或變數(此例為一個匿名函數)
console.log("e^{π} = " + exp(pi))

Class - 類別

1
2
3
4
class Shape {
constructor (id, x, y) {}
move (x, y) {}
}

還可以 extend

1
2
3
4
5
6
7
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y) // 呼叫父類別的建構元
this.radius = radius
super.move() // 取得父類別的函數或變數
}
}

類別可以設定 static 成員

1
2
3
4
5
6
7
class Circle extends Shape {
static whoami () {
console.log('I am Circle')
}
}
Circle.whoami() // I am Circle

可以自定義 getter & setter

1
2
3
4
5
6
7
8
9
10
class Circle {
constructor (radius) {
this._radius = radius
}
set radius (radius) { this._radius = radius }
get radius () { return this._radius }
get diameter () { return 2 * this._radius }
}
var c = new Circle(50) // 使用 new 來取得實體
c.diameter === 100

Set & Map - 兩個新的資料集合

set - 可以把它當成資料不會重複的 array

操作方法:add(), delete(), has(), clear()

1
2
3
4
let s = new Set()
s.add("hello").add("goodbye").add("hello")
for (let key of s.values()) // insertion order
console.log(key) // output : hello, goodbye

map - 可以把它當成 object,但 key 可以使用字串以外的型別

操作方法:set(), get(), delete, has(), clear()

1
2
3
4
5
6
7
let m = new Map()
let s = 1
m.set("hello", 42)
m.set(s, 34)
m.get(s) === 34
for (let [ key, val ] of m.entries())
console.log(key + " = " + val) // output : hello = 42, 1 = 34

列舉方法:set & map 都可以使用 keys(), values(), entries(), forEach(),且都有 size 屬性

weak set & weak map - 弱引用

共通點:

  • 適合存放 DOM 節點,因為當其中的 object 不再被引用的時候,記憶體會被回收,減少 memory leak
  • 成員只能是 object,其他的值不可用
  • 無法列舉,因此列舉方法與 size 屬性都不能用
  • 可以使用各自對應的操作方法,但少了 clear(),因為無法列舉
1
2
let isMarked = new WeakSet()
let attachedData = new WeakMap()

Symbol - 一個新的型別,代表獨一無二的值

1
2
3
4
5
6
7
8
9
Symbol("foo") !== Symbol("foo")
const foo = Symbol()
typeof foo === "symbol"
let obj = {}
obj[foo] = "foo" // 為一個物件加入 symbol 值必須使用 []
Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [ foo ]

可以使用 Symbol.for() 設定全域的 Symbol,此時會以 key 決定是否相等

1
Symbol.for("app.foo") === Symbol.for("app.foo")

Iterator - 使用 for…of 前必須宣告的函數

for…of 一種可以列舉 object, array, map, set 的方式,前提是要先宣告 iterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1
return {
next () {
[ pre, cur ] = [ cur, pre + cur ]
return { done: false, value: cur }
}
}
}
}
for (let n of fibonacci) {
if (n > 1000)
break
console.log(n)
}

Generator - 可以分段執行迴圈的函數

1
2
3
4
5
6
7
8
9
10
function* range (start, end, step) { // function 後面,函數名稱前面一定有個星號
while (start < end) {
yield start // 使用 yield 表示中斷,並回傳一個值
start += step
}
}
for (let i of range(0, 10, 2)) {
console.log(i) // 0, 2, 4, 6, 8
}

成員 Ganerator 表示法

1
2
3
4
5
6
class Clz {
* bar () {}
}
let Obj = {
* foo () {}
}

Promise - 確保異步操作結束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('Resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// Resolved

promise all

1
var p = Promise.all([p1, p2, p3]).then(success, fail);
  1. p1, p2, p3 全部完成才執行 success
  2. p1, p2, p3 任一個失敗就執行 fail

Proxy - 存取 object 之前的過濾器

1
2
3
4
5
6
7
8
9
10
let target = {
foo: "Welcome, foo"
}
let proxy = new Proxy(target, {
get (receiver, name) {
return name in receiver ? receiver[name] : `Hello, ${name}`
}
})
proxy.foo === "Welcome, foo"
proxy.world === "Hello, world"

可用的過濾有:get, set, has, deleteProperty, ……

Reflection - 改了舊的功能,但不可以直接蓋掉 object 原本的功能,所以只好放這裡

ES5 沒有 symbol ,所以舊的函數已不夠用

1
2
3
4
5
let obj = { a: 1 }
Object.defineProperty(obj, "b", { value: 2 })
obj[Symbol("c")] = 3
Object.getOwnPropertyNames(obj); // [ "a", "b" ]
Reflect.ownKeys(obj) // [ "a", "b", Symbol(c) ]