
本文翻譯自github上的一篇文章
原文地址:https://github.com/DrkSephy/es6-cheatsheet
es6-參考手冊(cè)
該手冊(cè)包括ES2015[ES6]的知識(shí)點(diǎn)、技巧、建議和每天工作用的代碼段例子。歡迎補(bǔ)充和建議。
var 和 let / const
除了var,我們現(xiàn)在有了兩種新的標(biāo)示符用來(lái)存儲(chǔ)值——let和const。與var不同的是,let和const 聲明不會(huì)提前到作用域的開頭。(譯注:即不發(fā)生聲明提前)
一個(gè)使用var的例子:
var snack = 'Meow Mix';
function getFood(food) {
if (food) {
var snack = 'Friskies';
return snack;
}
return snack;
}
getFood(false); // undefined
然而, 我們把var替換成let,觀察會(huì)發(fā)生什么:
let snack = 'Meow Mix';
function getFood(food) {
if (food) {
let snack = 'Friskies';
return snack;
}
return snack;
}
getFood(false); // 'Meow Mix'
這種行為變化提示我們,在使用var重構(gòu)遺留代碼的時(shí)候需要小心,盲目的把let替換成var會(huì)導(dǎo)致以外的行為
注意:
let和const具有塊作用域。因此在它們定義前調(diào)用會(huì)引發(fā)ReferenceError
console.log(x); // ReferenceError: x is not defined
let x = 'hi';
建議:在遺留代碼中的保留var聲明表示需要小心的重構(gòu)。在新建代碼庫(kù)時(shí),使用let聲明以后會(huì)只會(huì)發(fā)生改變的變量,用const聲明那些以后不會(huì)被改變的變量。
譯注:const修飾的基本類型不能改變,而其修飾的對(duì)象、函數(shù)、數(shù)組等引用類型,可以改變內(nèi)部的值,但不能改變其引用。
用塊(Blocks)替換立即執(zhí)行函數(shù)(IIFEs)
立即執(zhí)行函數(shù)常被用作閉包,把變量控制在作用域內(nèi)。在ES6中,我們可以創(chuàng)建一個(gè)塊作用域而且不僅僅是基于函數(shù)的作用域。
(function () {
var food = 'Meow Mix';
}());
console.log(food); // Reference Error
Using ES6 Blocks:
{
let food = 'Meow Mix';
};
console.log(food); // Reference Error
箭頭函數(shù)(Arrow Functions)
通常我們會(huì)建立嵌套函數(shù),當(dāng)我們想保留this上下文作用域的時(shí)候(該怎么辦?)。如下就是一個(gè)例子:
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character; // Cannot read property 'name' of undefined
});
};
一個(gè)常見(jiàn)的解決方法是利用一個(gè)變量存儲(chǔ)這個(gè)this的上下文。
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
var that = this; // Store the context of this
return arr.map(function (character) {
return that.name + character;
});
};
我們也可以傳入這個(gè)this的上下文:
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character;
}, this);
};
還可以用bind綁定這個(gè)上下文:
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(function (character) {
return this.name + character;
}.bind(this));
};
使用箭頭函數(shù),this的詞法作用域不會(huì)被影響,我們可以像以下這樣重寫之前的代碼
function Person(name) {
this.name = name;
}
Person.prototype.prefixName = function (arr) {
return arr.map(character => this.name + character);
};
建議: 只要當(dāng)你想保留this的詞法作用域時(shí),就使用箭頭函數(shù)
對(duì)于一個(gè)簡(jiǎn)單返回一個(gè)值的函數(shù)來(lái)說(shuō),箭頭函數(shù)顯得更加簡(jiǎn)潔
var squares = arr.map(function (x) { return x * x }); // Function Expression
const arr = [1, 2, 3, 4, 5];
const squares = arr.map(x => x * x); // Arrow Function for terser implementation
建議: 盡可能用箭頭函數(shù)替換你的函數(shù)定義
字符串(Strings)
在ES6中, 標(biāo)準(zhǔn)庫(kù)也在不斷的擴(kuò)充。在這些變化中就有很多方法可以用于字符串,比如.includes()和.repeat()
.includes()
var string = 'food';
var substring = 'foo';
console.log(string.indexOf(substring) > -1);
檢測(cè)返回值是否大于-1表示字符串是否存在,我們可以用.includes()替換,它返回一個(gè)boolean值。
const string = 'food';
const substring = 'foo';
console.log(string.includes(substring)); // true
.repeat()
function repeat(string, count) {
var strings = [];
while(strings.length < count) {
strings.push(string);
}
return strings.join('');
}
在ES6中,我們一種更簡(jiǎn)潔的實(shí)現(xiàn)方法:
// String.repeat(numberOfRepetitions)
'meow'.repeat(3); // 'meowmeowmeow'
模板字面量(Template Literals)
(譯注:原文是Template Literals,而非Template Strings)
利用模板字面量,我們可以直接在字符串使用特殊字符而不用轉(zhuǎn)義它們。
var text = "This string contains \"double quotes\" which are escaped.";
let text = `This string contains "double quotes" which don't need to be escaped anymore.`;
模板字面量還支持插值,可以輕松完成連接字符串和值的任務(wù):
var name = 'Tiger';
var age = 13;
console.log('My cat is named ' + name + ' and is ' + age + ' years old.');
const name = 'Tiger';
const age = 13;
console.log(`My cat is named ${name} and is ${age} years old.`);
在ES5中,我們這樣操作多行字符串:
var text = (
'cat\n' +
'dog\n' +
'nickelodeon'
);
或者
var text = [
'cat',
'dog',
'nickelodeon'
].join('\n');
模板字面量可以保留多行字符串,我們無(wú)需顯式的放置它們:
let text = ( `cat
dog
nickelodeon`
);
模板字面量可以接受表達(dá)式, 比如:
let today = new Date();
let text = `The time and date is ${today.toLocaleString()}`;
解構(gòu)賦值(Destructuring)
解構(gòu)賦值允許我們從數(shù)組或?qū)ο笾刑崛〕鲋?甚至深度嵌套的值),并把他們存入變量的簡(jiǎn)單語(yǔ)法
解構(gòu)數(shù)組(Destructuring Arrays)
var arr = [1, 2, 3, 4];
var a = arr[0];
var b = arr[1];
var c = arr[2];
var d = arr[3];
let [a, b, c, d] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 2
解構(gòu)對(duì)象(Destructuring Objects)
var luke = { occupation: 'jedi', father: 'anakin' };
var occupation = luke.occupation; // 'jedi'
var father = luke.father; // 'anakin'
let luke = { occupation: 'jedi', father: 'anakin' };
let {occupation, father} = luke;
console.log(occupation); // 'jedi'
console.log(father); // 'anakin'
模塊(Modules)
ES6之前,我們只用如Browserify的庫(kù)在客戶端創(chuàng)建模塊,并且需要用到Node.js。利用ES6,我們現(xiàn)在可以直接使用任何類型的模塊(AMD和CommonJS)
CommonJS中的exports
module.exports = 1;
module.exports = { foo: 'bar' };
module.exports = ['foo', 'bar'];
module.exports = function bar () {};
ES6中的export
在ES6中,提供各種不同類型的exports,我們可以運(yùn)行如下:
export let name = 'David';
export let age = 25;??
輸出對(duì)象列表:
function sumTwo(a, b) {
return a + b;
}
function sumThree(a, b, c) {
return a + b + c;
}
export { sumTwo, sumThree };
我們也可以簡(jiǎn)單地通過(guò)export關(guān)鍵字輸出函數(shù)、對(duì)象和值(等等):
export function sumTwo(a, b) {
return a + b;
}
export function sumThree(a, b, c) {
return a + b + c;
}
And lastly, we can export default bindings:
function sumTwo(a, b) {
return a + b;
}
function sumThree(a, b, c) {
return a + b + c;
}
let api = {
sumTwo,
sumThree
};
輸出默認(rèn)api:
/* Which is the same as
* export { api as default };
*/
建議:在模塊結(jié)束的地方,始終輸出默認(rèn)的方法。這樣可以清晰地看到接口,并且通過(guò)弄清楚輸出值的名稱節(jié)省時(shí)間。所以在CommonJS模塊中通常輸出一個(gè)對(duì)象或值。堅(jiān)持使用這種模式,會(huì)使我們的代碼易讀,并且可以輕松的在ES6和CommonJS中進(jìn)行插補(bǔ)。
ES6
ES6 提供提供各種不同的imports,我們輸入一整個(gè)文件:
import 'underscore';
這里值得注意的是,簡(jiǎn)單的輸入一文件會(huì)在文件的最頂層執(zhí)行代碼。和Python類似,我們已經(jīng)命名了imports:
import { sumTwo, sumThree } from 'math/addition';
我們還可以重命名這些已經(jīng)有名的imports:
import {
sumTwo as addTwoNumbers,
sumThree as sumThreeNumbers
} from 'math/addition';
此外,我們可以輸入各種東西(也叫做 namespace import)
import * as util from 'math/addition';
最后,我們可以從模塊輸入一列值:
import * as additionUtil from 'math/addition';
const { sumTwo, sumThree } = additionUtil;
如下這樣從默認(rèn)綁定進(jìn)行輸入
import api from 'math/addition';
// 例如: import { default as api } from 'math/addition';
雖然最好要保持輸出簡(jiǎn)單,但是如果我們需要,我們有時(shí)可以混用默認(rèn)輸入,當(dāng)我們想如下輸出的時(shí)候:
// foos.js
export { foo as default, foo1, foo2 };
我們可以如下輸入它們:
import foo, { foo1, foo2 } from 'foos';
當(dāng)使用commonj語(yǔ)法(如React)輸入一個(gè)模型的輸出時(shí),我們可以這樣做:
import React from 'react';
const { Component, PropTypes } = React;
這個(gè)也可以進(jìn)一步簡(jiǎn)化,使用:
import React, { Component, PropTypes } from 'react';
注意:輸出的值是綁定,不是引用。因此,綁定的值發(fā)生變化會(huì)影響輸出的模型中的值。避免修改這些輸出值的公共接口。
參數(shù)(Parameters)
在ES5中,我們可以很多方法操作函數(shù)參數(shù)的默認(rèn)值、未定義的參數(shù)和有定義的參數(shù)。在ES6中,我們可以用更簡(jiǎn)單的語(yǔ)法實(shí)現(xiàn)這一切。
默認(rèn)參數(shù)(Default Parameters)
function addTwoNumbers(x, y) {
x = x || 0;
y = y || 0;
return x + y;
}
在ES6中,我們可以簡(jiǎn)單的把默認(rèn)值賦給參數(shù):
function addTwoNumbers(x=0, y=0) {
return x + y;
}
addTwoNumbers(2, 4); // 6
addTwoNumbers(2); // 2
addTwoNumbers(); // 0
剩余參數(shù)(Rest Parameters)
在ES5中,我們這樣操作一個(gè)未定義的參數(shù):
function logArguments() {
for (var i=0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
使用休止符(...)我們可以傳入大量未定義的參數(shù):
function logArguments(...args) {
for (let arg of args) {
console.log(arg);
}
}
已命名的參數(shù)(Named Parameters)
ES5中,一種處理已命名參數(shù)的方式是使用選項(xiàng)方式,這種方法來(lái)自jQuery。
function initializeCanvas(options) {
var height = options.height || 600;
var width = options.width || 400;
var lineStroke = options.lineStroke || 'black';
}
通過(guò)解構(gòu)成正式參數(shù)的方式,我們可以實(shí)現(xiàn)同樣的功能:
function initializeCanvas(
{ height=600, width=400, lineStroke='black'}) {
// Use variables height, width, lineStroke here
}
如果我們想使全部參數(shù)值可選,我們可以用一個(gè)空對(duì)象這樣結(jié)構(gòu):
function initializeCanvas(
{ height=600, width=400, lineStroke='black'} = {}) {
// ...
}
展開運(yùn)算符(Spread Operator)
在ES5中,查找一個(gè)array中的最大值需要使用Math.max的apply方法:
Math.max.apply(null, [-1, 100, 9001, -32]); // 9001
在es6中,我們使用展開運(yùn)算符將array傳遞給函數(shù)作為參數(shù):
Math.max(...[-1, 100, 9001, -32]); // 9001
我們可以用這樣簡(jiǎn)潔的語(yǔ)法鏈接數(shù)組字面量:
let cities = ['San Francisco', 'Los Angeles'];
let places = ['Miami', ...cities, 'Chicago']; // ['Miami', 'San Francisco', 'Los Angeles', 'Chicago']
類(classes)
在ES6之前,我們通過(guò)創(chuàng)建構(gòu)造器函數(shù),并且在其prototype上添加屬性的方法創(chuàng)建一個(gè)類:
function Person(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Person.prototype.incrementAge = function () {
return this.age += 1;
};
并且用一下方法創(chuàng)建繼承類:
function Personal(name, age, gender, occupation, hobby) {
Person.call(this, name, age, gender);
this.occupation = occupation;
this.hobby = hobby;
}
Personal.prototype = Object.create(Person.prototype);
Personal.prototype.constructor = Personal;
Personal.prototype.incrementAge = function () {
Person.prototype.incrementAge.call(this);
this.age += 20;
console.log(this.age);
};
ES6 提供了十分有用的句法在后臺(tái)實(shí)現(xiàn)這一切,我們可以這樣直接創(chuàng)建一個(gè)類:
class Person {
constructor(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
incrementAge() {
this.age += 1;
}
}
并且用關(guān)鍵字extends實(shí)現(xiàn)繼承:
class Personal extends Person {
constructor(name, age, gender, occupation, hobby) {
super(name, age, gender);
this.occupation = occupation;
this.hobby = hobby;
}
incrementAge() {
super.incrementAge();
this.age += 20;
console.log(this.age);
}
}
建議:使用ES6的語(yǔ)法創(chuàng)建類模糊了后臺(tái)的實(shí)現(xiàn)和原型如何工作,這個(gè)好特性可以使我們的代碼更整潔。
Symbols
Symbol在ES6之前就已經(jīng)出現(xiàn)了, 但是現(xiàn)在我們有了一個(gè)公共的接口可以直接使用。Symbol是唯一且不可改變的值,被用作哈希中的鍵。
Symbol()
調(diào)用Symbol()或者Symbol(description)會(huì)創(chuàng)建一個(gè)不能在全局查找的獨(dú)一無(wú)二的符號(hào)。一種使用symbol()的情況是,利用自己的邏輯修補(bǔ)第三方的對(duì)象或命名空間,但不確定會(huì)不會(huì)在庫(kù)更新時(shí)產(chǎn)生沖突。例如,如果你想添加一個(gè)方法refreshCompontent到React.Component,并且確信這個(gè)方法他們不會(huì)在以后的更新中添加。
const refreshComponent = Symbol();
React.Component.prototype[refreshComponent] = () => {
// do something
}
###Symbol.for(key)
Symbol.for(key) 依然會(huì)創(chuàng)建一個(gè)唯一且不能修改的Symbol,但是它可以在全局被查找。兩次調(diào)用相同的Symbol.for(key) 會(huì)創(chuàng)建一樣的Symbol實(shí)例。注意,他和Symbol(description)不是相同的:
Symbol('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol('foo') // false
Symbol.for('foo') === Symbol.for('foo') // true
一個(gè)常見(jiàn)的symbol方法Symbol.for(key)是可互操作的。(使用這個(gè)方法)這個(gè)可以通過(guò)使用自己的代碼在包括已知接口的第三方的對(duì)象參數(shù)中查找symbol成員實(shí)現(xiàn),例如:
function reader(obj) {
const specialRead = Symbol.for('specialRead');
if (obj[specialRead]) {
const reader = obj[specialRead]();
// do something with reader
} else {
throw new TypeError('object cannot be read');
}
}
在另一個(gè)庫(kù)中:
const specialRead = Symbol.for('specialRead');
class SomeReadableType {
[specialRead]() {
const reader = createSomeReaderFrom(this);
return reader;
}
}
ES6中,一個(gè)值得注意的是關(guān)于Symbol的互操作性的例子是Symbol.iterator,它存在于Arrays、Strings、Generators等等的所有可迭代類型中。當(dāng)作為一個(gè)方法調(diào)用的時(shí)候,它會(huì)返回一個(gè)具有迭代器接口的對(duì)象。
Maps
Maps是JavaScript中十分有用的結(jié)構(gòu)。在ES6之前, 我們通過(guò)對(duì)象創(chuàng)建哈希maps:
var map = new Object();
map[key1] = 'value1';
map[key2] = 'value2';
但是,這樣不能保護(hù)我們對(duì)已有屬性以外的重寫:
> getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned');
> TypeError: Property 'hasOwnProperty' is not a function
Map允許我們使用set、get和search(等等)訪問(wèn)屬性值。
let map = new Map();
> map.set('name', 'david');
> map.get('name'); // david
> map.has('name'); // true
最意想不到的是Map不再限制我們只使用字符串作為鍵,我們現(xiàn)在可以使用任何類型作為鍵而不會(huì)發(fā)生類型轉(zhuǎn)換。
let map = new Map([
['name', 'david'],
[true, 'false'],
[1, 'one'],
[{}, 'object'],
[function () {}, 'function']
]);
for (let key of map.keys()) {
console.log(typeof key);
// > string, boolean, number, object, function
}
注意:當(dāng)使用如
map.get()等方法測(cè)試相等的時(shí)候,諸如function和object這樣的非原始值不能正常工作。因此,依然應(yīng)該使用原始值(作為鍵),比如String、Boolean和Number。
我們也可以使用.entries()方法作為迭代器遍歷Map
for (let [key, value] of map.entries()) {
console.log(key, value);
}
WeakMaps
ES6之前,為了保存私有數(shù)據(jù),我們采取了很多方式。其中一個(gè)方法就是命名轉(zhuǎn)換:
class Person {
constructor(age) {
this._age = age;
}
_incrementAge() {
this._age += 1;
}
}
但是命名轉(zhuǎn)換會(huì)引起代碼庫(kù)混亂,并且不能保證總是被支持。為此,我們使用WeakMaps存儲(chǔ)數(shù)據(jù):
let _age = new WeakMap();
class Person {
constructor(age) {
_age.set(this, age);
}
incrementAge() {
let age = _age.get(this) + 1;
_age.set(this, age);
if (age > 50) {
console.log('Midlife crisis');
}
}
}
使用WeakMap存儲(chǔ)數(shù)據(jù)時(shí)的一個(gè)很有趣的事情是,這個(gè)key不會(huì)暴露出屬性名,需要使用Reflect.ownKeys()實(shí)現(xiàn):
> const person = new Person(50);
> person.incrementAge(); // 'Midlife crisis'
> Reflect.ownKeys(person); // []
使用WeakMap更實(shí)際的例子是在不污染DOM自身的情況下存儲(chǔ)與DOM元素相關(guān)的數(shù)據(jù):
let map = new WeakMap();
let el = document.getElementById('someElement');
// 給元素存一個(gè)弱引用
map.set(el, 'reference');
// 獲得元素的值
let value = map.get(el); // 'reference'
// 移除引用
el.parentNode.removeChild(el);
el = null;
// 元素被回收后,map是空的
如上所示,當(dāng)一個(gè)對(duì)象被GC回收后,WeakMap會(huì)自動(dòng)移除以其為標(biāo)識(shí)符的鍵值對(duì)。
注意:為了進(jìn)一步說(shuō)明這個(gè)例子的實(shí)用性。當(dāng)一個(gè)與DOM對(duì)應(yīng)的對(duì)象的具有引用時(shí),考慮jQuery如何存儲(chǔ)它。使用WeakMaps,jQuery可以在DOM元素被刪除時(shí)自動(dòng)釋放與之關(guān)聯(lián)的內(nèi)存??偠灾瑢?duì)任何庫(kù)而言,WeakMaps對(duì)操作DOM元素是非常實(shí)用的。
Promises
Promise允許我們把水平的代碼(回調(diào)函數(shù)的地獄):
func1(function (value1) {
func2(value1, function (value2) {
func3(value2, function (value3) {
func4(value3, function (value4) {
func5(value4, function (value5) {
// Do something with value 5
});
});
});
});
});
轉(zhuǎn)換為豎直的代碼:
func1(value1)
.then(func2)
.then(func3)
.then(func4)
.then(func5, value5 => {
// Do something with value 5
});
在ES6之前,我們使用bluebird或是Q,現(xiàn)在我們有了Promises:
new Promise((resolve, reject) =>
reject(new Error('Failed to fulfill Promise')))
.catch(reason => console.log(reason));
這里我們有2個(gè)handlers,resolve(Promise執(zhí)行成功時(shí)調(diào)用的函數(shù))和reject(Promise失敗時(shí)調(diào)用的函數(shù))。
使用Promise的好處:使用嵌套的回調(diào)函數(shù)處理錯(cuò)誤會(huì)很混亂。使用Promise,我們可以很清晰的使錯(cuò)誤冒泡,并且就近處理它們。更好的是,在它處理成功(或失?。┲驪romise的值是不可修改的。
以下是個(gè)使用Promise的實(shí)例:
var request = require('request');
return new Promise((resolve, reject) => {
request.get(url, (error, response, body) => {
if (body) {
resolve(JSON.parse(body));
} else {
resolve({});
}
});
});
我們可以使用Promise.all()并行的處理一個(gè)異步操作數(shù)組:
let urls = [
'/api/commits',
'/api/issues/opened',
'/api/issues/assigned',
'/api/issues/completed',
'/api/issues/comments',
'/api/pullrequests'
];
let promises = urls.map((url) => {
return new Promise((resolve, reject) => {
$.ajax({ url: url })
.done((data) => {
resolve(data);
});
});
});
Promise.all(promises)
.then((results) => {
// Do something with results of all our promises
});
Generators
和Promise使我們避免回調(diào)函數(shù)的地獄相似,Generators可以扁平化我們的代碼——給我們一種同步執(zhí)行異步代碼的感覺(jué),Generators是個(gè)很重要的函數(shù),它使我們可以暫停操作的執(zhí)行,隨后返回表達(dá)式的值。
下面是使用Generator的一個(gè)簡(jiǎn)單例子:
function* sillyGenerator() {
yield 1;
yield 2;
yield 3;
yield 4;
}
var generator = sillyGenerator();
> console.log(generator.next()); // { value: 1, done: false }
> console.log(generator.next()); // { value: 2, done: false }
> console.log(generator.next()); // { value: 3, done: false }
> console.log(generator.next()); // { value: 4, done: false }
這里,next()使我們generator繼續(xù)推進(jìn),并且得到新的表達(dá)式的值(譯注:每次推進(jìn)到下一個(gè)yield值)。當(dāng)然,上面的例子很牽強(qiáng),我們可以利用Generator以同步的方式寫異步代碼:
// 利用Generator屏蔽異步過(guò)程
function request(url) {
getJSON(url, function(response) {
generator.next(response);
});
}
下面我們寫一個(gè)generator函數(shù)用來(lái)返回我們自己的數(shù)據(jù):
function* getData() {
var entry1 = yield request('http://some_api/item1');
var data1 = JSON.parse(entry1);
var entry2 = yield request('http://some_api/item2');
var data2 = JSON.parse(entry2);
}
利用yield的功能,我們確保entry1可以獲得返回的數(shù)據(jù),用于解析并存儲(chǔ)到data1中。
當(dāng)我們利用generator以同步的方式寫異步的代碼時(shí),其中的錯(cuò)誤不會(huì)簡(jiǎn)單清晰的傳遞。因此,我們利用Promise加強(qiáng)generator:
function request(url) {
return new Promise((resolve, reject) => {
getJSON(url, resolve);
});
}
我們寫了一個(gè)函數(shù),利用next用來(lái)按序地一步步遍歷generator。該函數(shù)利用上述的請(qǐng)求方式并yeild一個(gè)Promise(對(duì)象)。
function iterateGenerator(gen) {
var generator = gen();
(function iterate(val) {
var ret = generator.next();
if(!ret.done) {
ret.value.then(iterate);
}
})();
}
通過(guò)Promise加強(qiáng)generator后,我們可以利用Promise.catch和Promise.reject這樣清晰的方式傳播錯(cuò)誤。只用這個(gè)加強(qiáng)版的Generator和以前一樣簡(jiǎn)單:
iterateGenerator(function* getData() {
var entry1 = yield request('http://some_api/item1');
var data1 = JSON.parse(entry1);
var entry2 = yield request('http://some_api/item2');
var data2 = JSON.parse(entry2);
});
我們可以重用寫好的代碼,像過(guò)去使用Generator一樣,這一點(diǎn)很強(qiáng)大。當(dāng)我們利用generator以同步的方式寫異步的代碼的同時(shí),利用一個(gè)不錯(cuò)的方式保留了錯(cuò)誤傳播的能力,我們實(shí)際上可以利用一個(gè)更為簡(jiǎn)單的方式達(dá)到同樣的效果:異步等待(Async-Await)。
Async Await
這是一個(gè)在ES2016(ES7)中即將有的特性,async await允許我們更簡(jiǎn)單地使用Generator和Promise執(zhí)行和已完成工作相同的任務(wù):
var request = require('request');
function getJSON(url) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, body) {
resolve(body);
});
});
}
async function main() {
var data = await getJSON();
console.log(data); // NOT undefined!
}
main();
在后臺(tái),它的實(shí)現(xiàn)類似Generators。我(作者)強(qiáng)烈建議使用這個(gè)替代Generators + Promises。還會(huì)有很多的資源出現(xiàn)并使用ES7,同時(shí),Babel也會(huì)用在這里。
Getter 和 Setter 函數(shù)
ES6 已經(jīng)支持了Getter和Setter函數(shù),例如:
class Employee {
constructor(name) {
this._name = name;
}
get name() {
if(this._name) {
return 'Mr. ' + this._name.toUpperCase();
} else {
return undefined;
}
}
set name(newName) {
if (newName == this._name) {
console.log('I already have this name.');
} else if (newName) {
this._name = newName;
} else {
return false;
}
}
}
var emp = new Employee("James Bond");
// 內(nèi)部使用了get方法
if (emp.name) {
console.log(emp.name); // Mr. JAMES BOND
}
// 內(nèi)部使用了setter(譯注:原文中這一句和上一句注釋的表述就這么不一樣)
emp.name = "Bond 007";
console.log(emp.name); // Mr. BOND 007
最新的瀏覽器都支持對(duì)象中的getter/setter函數(shù),我們可以使用他們計(jì)算屬性、添加事件以及在setting和getting前的預(yù)處理
var person = {
firstName: 'James',
lastName: 'Bond',
get fullName() {
console.log('Getting FullName');
return this.firstName + ' ' + this.lastName;
},
set fullName (name) {
console.log('Setting FullName');
var words = name.toString().split(' ');
this.firstName = words[0] || '';
this.lastName = words[1] || '';
}
}
person.fullName; // James Bond
person.fullName = 'Bond 007';
person.fullName; // Bond 007