<style>
.reveal, .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 {
	font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, "Microsoft JhengHei", Meiryo, "ＭＳ ゴシック", "MS Gothic", sans-serif;
}
h1, h2, h3, h4, h5, h6 {
	text-transform: none !important;
}
.js-img {
	background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/480px-JavaScript-logo.png) center/contain;
	width: 350px;
	height: 350px;
	display: block;
	margin: 20px auto !important;
	border: 4px solid white !important;
}
</style>

# ECMAScript 6 簡介
###### ECMAScript (ES) 6 = ECMAScript 2015

Cheng-Han Wu<br />[@jackymaxj](https://twitter.com/jackymaxj)

**參考自**  
[Introduction to ECMAScript 6](http://coenraets.org/present/es6)  
Christophe Coenraets<br/>[@ccoenraets](https://twitter.com/ccoenraets)

---

<img src="https://avatars2.githubusercontent.com/u/2639151?v=3&s=460" style="width:150px;height:150px;border-radius:50%"/>

Cheng-Han Wu  
Taipei, Taiwan  
@jackymaxj  
https://hackmd.io  
https://github.com/jackycute

---

## 大綱

- Status 發展現況
- Variables & Constants 變數與常數
- Destructuring 解構
- Arrow Functions 箭號函數
- Promises
- Modules 模組
- Classes 類別
- Template Strings 樣板字串
- Generators
- Collections 集合

---

<div class="js-img"></div>

# 發展現況

----

## 專有名詞

- *JavaScript:* 語言的名稱
- *ECMAScript:* 語言的標準
- *TC 39:* 技術委員會
- *ECMAScript Harmony:* ES 5 後期改善
- *ECMAScript.Next:* 下一版本的代號
- *ECMAScript 6:* 下一版本的最終名稱

----

## 歷史演進

- *ECMAScript 1:* 1997
- *ECMAScript 2:* 1998
- *ECMAScript 3:* 1999
- *ECMAScript 4:* 拋棄
- *ECMAScript 5:* 2009
- *ECMAScript 6:* ?

----

## ECMAScript 6 目標
### 為了更好的支援：

- Complex Apps 複雜的應用程式
- Libraries 函式庫
- Code Generators 程式碼產生器

----

### 避免程式核心功能的各種不一致與分散性

Modules 模組, Promises, Classes 類別, 等等

----

## 向下相容性

> “不能讓網頁壞掉”

也就是說不能亂改 var 功能

----

## 什麼時候可以用？

- 相容性表格  
  請見：https://kangax.github.io/compat-table/es6  
- 關注 [@esdiscuss](https://twitter.com/esdiscuss)

----

## 今天就開始用 ES6

轉譯器

- Babel  
  http://babeljs.io
- Traceur  
  https://github.com/google/traceur-compiler
- TypeScript  
  <small>(JavaScript 的延伸，同時也致力於符合 ECMAScript 6)</small>  
  http://www.typescriptlang.org

---

<div class="js-img"></div>

# 變數與常數

----

## var

函數內有效

```javascript=
function divide(x, y) {
    if (y !== 0) {
        var result;
        result = x / y;
    }
    return result;
}
console.log(divide(10, 2)); // 5
```

----

## let

區塊內有效

```javascript=
function divide(x, y) {
    if (y !== 0) {
        let result;
        result = x / y;
    }
    return result;  // throws Error
}
console.log(divide(10, 2));
```

----

### const

區塊內有效

```javascript=
const PI = 3.14159265359;
const COLOR = {
    name: "Red",
    hexValue: "#FF0000"
};
```
不能重新給值或是重新定義

----

## 從變數建立物件

ECMAScript 5

```javascript=
var firstName = "Christophe";
var lastName = "Coenraets";
var twitterId = "@ccoenraets";

var speaker = {
    firstName: firstName,
    lastName: lastName,
    twitterId: twitterId
};
```

----

## 從物件建立變數

ES6 Object Literals 物件字面

```javascript=
let firstName = "Christophe";
let lastName = "Coenraets";
let twitterId = "@ccoenraets";

let speaker = {firstName, lastName, twitterId};
```
<small>用 var 也可以</small>

---

<div class="js-img"></div>

# 解構

使用語法來對應陣列或是物件結構的字面  
進而從中抽離資料

----

## 從陣列元素中建立變數

ECMAScript 5

```javascript=
var colors = ["red", "green", "blue"];

var primary   = colors[0];
var secondary = colors[1];
var tertiary  = colors[2];

console.log(primary);   // red
console.log(secondary); // green
console.log(tertiary);  // blue
```

----

## Spread Operator 分散運算子

```javascript=
var colors = ["red", "green", "blue", "yellow", "orange"];

var [primary, secondary, ...otherColors] = colors;

console.log(primary);     // red
console.log(secondary);   // green
console.log(otherColors); // [ 'blue', 'yellow', 'orange']
```

----

## 多回傳值的函數

```javascript=
function getDate() {
    var d = new Date();
    return [d.getDate(), d.getMonth() + 1, d.getFullYear()];
}

var [day, month, year] = getDate();
console.log(day);   // 4
console.log(month); // 5
console.log(year);  // 2015
```

----

## 從物件屬性建立變數

ECMAScript 5

```javascript=
var speaker = { firstName: "Christophe",
                lastName: "Coenraets",
                twitterId: "@ccoenraets" };

var firstName = speaker.firstName;
var lastName = speaker.lastName;
var twitterId = speaker.twitterId;

console.log(firstName); // Christophe
console.log(lastName);  // Coenraets
console.log(twitterId); // @ccoenraets
```

----

## 從物件屬性建立變數

ES6 Object Destructuring 物件解構

```javascript=
var speaker = { firstName: "Christophe",
                lastName: "Coenraets",
                twitterId: "@ccoenraets" };

var {firstName, lastName, twitterId} = speaker;

console.log(firstName); // Christophe
console.log(lastName);  // Coenraets
console.log(twitterId); // @ccoenraets
```
```javascript=
var {fName: firstName, lName: lastName, twId:twitterId} = speaker;
console.log(fName); // Christophe
```

---

<div class="js-img"></div>

# Arrow Functions<br>箭號函數

----

ES5 Function

```javascript=
var greeting = function(message, name) {
    return message + ' ' + name;
}

console.log(greeting('Hello', 'Christophe'));
```

ES6 Arrow Function
<!-- .element: class="fragment" data-fragment-index="2" -->

```javascript=
var greeting = (message, name) => {
    return message + ' ' + name;
}
```
<!-- .element: class="fragment" data-fragment-index="2" -->

```javascript=
var greeting = (message, name) => message + ' ' + name;
```
<!-- .element: class="fragment" data-fragment-index="3" -->

```javascript=
var greeting = name  => 'Hello ' + name;
```
<!-- .element: class="fragment" data-fragment-index="4" -->

----

再一個範例

```javascript=
var array = [1, 2, 3];
var total = 0;
array.forEach(function(item) {
    total = total + item;
});
console.log(total);
```

```javascript=
var array = [1, 2, 3];
var total = 0;
array.forEach(item => total = total + item);
console.log(total);
```
<!-- .element: class="fragment" data-fragment-index="1" -->

----

ECMAScript 5

> “var self = this” 也就是 “var that = this”

```javascript=
var obj = {
    init: function () {
        var self = this;
        setTimeout(function() {
            self.doSomething();
        }, 1000);
    },
    doSomething: function() {
        console.log("doing something in ES5");
    }
};
obj.init();
```

----

ES 6 Arrow Functions

真正的 “this”

```javascript=
var obj = {
    init: function() {
        setTimeout(() => this.doSomething(), 1000);
    },
    doSomething: function() {
        console.log("doing something in ES6");
    }
};
obj.init();
```

----

Default Params 預設參數

```javascript=
var greeting = (name, msg="Hello") => msg + ' ' + name;

console.log(greeting('Christophe', 'Hi')); // Hi Christophe
console.log(greeting('Christophe'));       // Hello Christophe
```

"function" 也可以用：
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
function greeting(name, message="Hello") {
    return message + ' ' + name;
}
```
<!-- .element: class="fragment" data-fragment-index="2" -->

---

<div class="js-img"></div>

# Promises

----

## 地獄回傳金字塔

```javascript=
step1(function (value1) {
    step2(value1, function(value2) {
        step3(value2, function(value3) {
            step4(value3, function(value4) {
                // Do something with value4
            });
        });
    });
});
```
<small>https://github.com/kriskowal/q</small>

----

## 回傳的問題

1. 難以組成 (循序或是同步)
2. 難以處理錯誤
3. 不合理的輸入參數與回傳值的語意

----

# Promise

尚未可用的值之代理者

1. 非同步函數回傳 promise
2. 呼叫者帶著 event handler 回傳 promise
3. 當 Event handler 有結果的時候處理它


  ➝ 清楚的輸入參數與回傳值的語意

----

## q Promises

定義

```javascript=
function step1() {
    var deferred = Q.defer();
    FS.readFile("foo.txt", "utf-8", function (error, text) {
        if (error) {
            deferred.reject(new Error(error));
        } else {
            deferred.resolve(text);
        }
    });
    return deferred.promise;
}
```

----

## q Promises

使用

```javascript=
Q.fcall(step1)
    .then(step2)
    .then(step3)
    .then(step4)
    .then(function(value4) {
        // Do something with value4
    })
    .catch(function(error) {
        // Handle any error from all above steps
    })
    .done();
```
<small>
請把 *then(handler)* 想成 *addEventListener("done", handler)*
</small>

----

## jQuery Promises

定義

```javascript=
function getList() {
    var deferred = $.Deferred();
    if (list) {
        deferred.resolve(list);
    } else {
        deferred.reject("no list");
    }
    return deferred.promise();
}
```

使用
<!-- .element: class="fragment" data-fragment-index="1" -->
```javascript=
service.getList()
    .done(function(list) {
        console.log(list);
    })
    .fail(function(error) {
        console.log(error);
    });
```
<!-- .element: class="fragment" data-fragment-index="1" -->

----

## ECMAScript 6 Promises

定義

```javascript=
function timeout(millis) {
    var promise = new Promise(function (resolve, reject) {
        setTimeout(function() {
            resolve();
        }, millis);
    });
    return promise;
}
```

使用
<!-- .element: class="fragment" data-fragment-index="1" -->
```javascript=
timeout(1000).then(function() {
    console.log('done waiting');
});
```
<!-- .element: class="fragment" data-fragment-index="1" -->
Promisified setTimeout()
<!-- .element: class="fragment" data-fragment-index="2" -->

----

## ECMAScript 6 Promises

定義 假資料服務 (Service)

```javascript=
var employees;

function findAll() {
    return new Promise(function (resolve, reject) {
        if (employees) {
            resolve(employees);
        } else {
            reject("employees is not defined");
        }
    });
}
```

----

## ECMAScript 6 Promises

使用 假資料服務 (Service)

```javascript=
findAll()
    .then(function(employees) {
        console.log(employees);
    })
    .catch(function(error) {
        console.log(error);
    });
```

---

<div class="js-img"></div>

# 模組

----

## AMD 模組

```javascript=
define(function (require) {

    var $ = require('jquery');

    var findAll = function() {
        // implementation
    };

    var findById = function(id) {
        // implementation
    };

    return {
        findAll: findAll,
        findById: findById
    };

});
```

----

Common.js 模組

```javascript=
var findAll = function () {
    // implementation
};

var findById = function(id) {
    // implementation
};

module.exports = {
    findAll: findAll,
    findById: findById
};
```

----

## ECMAScript 6 模組

定義

```javascript=
// datelib.js
export const today = new Date();

export var shortDate = function() {
    return today.getMonth() + 1 + '/' +
           today.getDate() + '/' +
           today.getFullYear();
}
```

使用
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
import {today, shortDate} from './datelib';
console.log(today);       // Mon May 4 2015 11:04:06...
console.log(shortDate()); // 5/4/2015
import * as date from "./datelib";
console.log(date.today);
console.log(date.shortDate());
```
<!-- .element: class="fragment" data-fragment-index="1" -->

----

## ECMAScript 6 模組

定義 假資料 (Service)

```javascript=
export function findAll() {
    // implementation
}

export function findById(id) {
    // implementation
}

export var endpoint = "http://localhost:5000";
```

使用 假資料 (Service)
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
import * as employeeService from "employee";

employeeService.findAll().then(function(employees) {
    console.log(employees);
});
```
<!-- .element: class="fragment" data-fragment-index="1" -->

---

<div class="js-img"></div>

# 類別

----

## ECMAScript 6 類別

```javascript=
class Mortgage {
	
    constructor(amount, years, rate) {
        this.amount = amount;
        this.years = years;
        this.rate = rate;
    }
	
    calculate() {
        // No interest mortgage for ES6 fans
        return this.amount / (this.years * 12);
    }
	
}

let m = new Mortgage(200000, 30, 3);
console.log(m.calculate());
```

----

## ECMAScript 6 類別

```javascript=
class Circle extends Shape {

    constructor(x, y, radius) {
        super(x, y);
        this.radius = radius;
    }

    static get pi() {
        return 3.14159265359;
    }

    get circumference() {
        return 2 * Circle.pi * this.radius;
    }

    render() {
        console.log('Rendering circle');
    }

}
```

----

## ECMAScript 6 類別

```javascript=
var c = new Circle(0, 0, 10);
console.log(c.x);             // 0
c.x = 5;
console.log(c.x);             // 5
console.log(Circle.pi);       // 3.14159265359
console.log(c.circumference); // 62.8318530718
c.render();                   // Rendering circle
```

---

<div class="js-img"></div>

# 樣板字串

----

## 樣板字串

```javascript=
var str = `Hello World!`
console.log(str);
```

```javascript=
var multiLine = `This is an example
    of a multiline string`;
console.log(multiLine);
```
<!-- .element: class="fragment" data-fragment-index="1" -->

----

## 字串替換

```javascript=
var name = "Christophe";
console.log(`Hello, ${name}!`);
```

```javascript=
var user = {firstName: "Lisa", lastName: "Wong"};
console.log(`Hello, ${user.firstName} ${user.lastName}!`);
```
<!-- .element: class="fragment" data-fragment-index="1" -->

----

## 表達式

```javascript=
console.log(`Today is ${new Date()}!`);
```

```javascript=
var price = 100;
var exchangeRate = 0.89;
console.log(`Price in Euro: ${price * exchangeRate}`);
```
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
console.log(`Hello, ${user.firstName} ${user.lastName}!
Today is ${new Date()}`);
```
<!-- .element: class="fragment" data-fragment-index="2" -->

---

<div class="js-img"></div>

# Generators

----

## 什麼是 Generator？

- 使用 *function\** 宣告的特殊函數，屬工廠模式 (Factory Pattern)
- 使用 *yield* 可以在任何地方脫離函數
- 當再次進入時，會回復到與之前相同的點與相同的狀態

----

## Generator 範例

```javascript=
function* idMaker(){
    var index = 0;
    while(index < 3) {
        yield index++;
    }
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
```

---

<div class="js-img"></div>

# 集合

----

## ES5 "Map"

```javascript=
var settings = {};
settings.server = "http://localhost";
settings.userName = "Christophe";
settings["language"] = "EN";
```
鍵必須是字串

## ES6 Map
<!-- .element: class="fragment" data-fragment-index="1" -->

```javascript=
var map = new Map();
map.set("server", "http://localhost");
map.set("userName", "Christophe");
map.get("userName");
map.has("userName");
map.delete("userName");
```
<!-- .element: class="fragment" data-fragment-index="1" -->

鍵可以是任何東西
<!-- .element: class="fragment" data-fragment-index="1" -->

----

## WeakMap

- 跟 Map 很像
- 鍵必須是物件
- 不會防止鍵被垃圾回收 (GC)
- 對於防止記憶體洩漏很有用
- 不能被迭代 (iterated)

----

## Set

有排序的不重複隨意值
```javascript=
var colors = new Set();
colors.add("red");
colors.add("blue");
console.log(colors.size); // 2;
console.log(colors.has("red")); // true;
colors.delete("red");
```

----

## WeakSet

- 跟 Set 很像
- 值必須是物件
- 不會防止值被垃圾回收 (GC)
- 不能迭代 (iterated)

---

# 參考資料

- [ECMAScript 6 Spec](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts)
- [ECMAScript 6 on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla)
- [2ality.com](http://www.2ality.com/)
- [ECMAScript 6 Tools](https://github.com/addyosmani/es6-tools)
- [Babel](http://babeljs.io/)
- [Traceur](https://github.com/google/traceur-compiler)

---

## 謝謝！歡迎指教

[@jackymaxj](https://twitter.com/jackymaxj)  

原作者：[@ccoenraets](https://twitter.com/ccoenraets)

> 喜歡這份簡報嗎？你也來寫一份吧！
> https://goo.gl/CfG0hH