Tip
最近讀完了 Nicholas C. Zakas 的新書 深入理解ES6跷敬,根據(jù)之前的經(jīng)驗和一些文檔梳理的知識脈絡麻车,總結一些關于 ES6 的常用方法和技巧。
1. let/const 特性
在 ES6 標準發(fā)布之前受裹,JS 一般都是通過關鍵字var
聲明變量碌补,與此同時,并不存在明顯的代碼塊聲明棉饶,想要形成代碼塊厦章,一般都是采用閉包的方式,舉個十分常見的例子:
var arr = []
for(var i = 0; i < 5; i++) {
arr.push(function() {
console.log(i)
})
}
arr.forEach(function(item) {
item()
})
// 輸出5次數(shù)字5
關于為什么輸出的全是數(shù)字5照藻,涉及到了JS的事件循環(huán)機制袜啃,異步隊列里的函數(shù)執(zhí)行的時候,由于關鍵字var
不會生成代碼塊岩梳,所以參數(shù)i = 5
囊骤,最后也就全輸出了數(shù)字5。用之前的方法我們可以這樣修改:
var arr = []
for(var i = 0; i < 5; i++) {
(function(i) {
arr.push(function() {
console.log(i)
})
})(i)
}
arr.forEach(function(item) {
item()
})
// 輸出 0 1 2 3 4
而在引入let
和const
之后冀值,這兩個關鍵字會自動生成代碼塊也物,并且不存在變量提升,因此只需要把var
關鍵字換成let
就可以輸出數(shù)字0到4了:
var arr = []
for(let i = 0; i < 5; i++) {
arr.push(function() {
console.log(i)
})
}
arr.forEach(function(item) {
item()
})
// 輸出 0 1 2 3 4
關鍵字let
和const
的區(qū)別在于列疗,使用const
聲明的值類型變量不能被重新賦值锉屈,而引用類型變量是可以的洲押。
變量提升是因為瀏覽器在編譯執(zhí)行JS代碼的時候,會先對變量和函數(shù)進行聲明,
var
關鍵字聲明的變量也會默認為undefined
粘优,在聲明語句執(zhí)行時再對該變量進行賦值。
值得注意的是肴敛,在重構原先代碼的過程中璃哟,要十分注意,盲目地使用let
來替換var
可能會出現(xiàn)出乎意料的情況:
var snack = 'Meow Mix'
function getFood(food) {
if (food) {
var snack = 'Friskies'
return snack
}
return snack
}
getFood(false)
// undefined
替換之后會出現(xiàn)與原先輸出不匹配的情況产艾,至于原因疤剑,就是上面提到的let
不存在變量提升滑绒。
使用var
雖然沒有執(zhí)行if
內(nèi)的語句,但是在聲明變量的時候已經(jīng)聲明了var snack = undefined
的局部變量隘膘,最后輸出的是局部變量里的undefined
疑故。
let snack = 'Meow Mix'
function getFood(food) {
if (food) {
let snack = 'Friskies'
return snack
}
return snack
}
getFood(false)
// 'Meow Mix'
而使用let
則在不執(zhí)行if
語句時拿不到代碼塊中局部的snack
變量(在臨時死區(qū)中),最后輸出了全局變量中的snack
弯菊。
當前使用塊級綁定的最佳實踐是:默認使用
const
纵势,只在確實需要改變變量的值時使用let
。這樣就可以在某種程度上實現(xiàn)代碼的不可變管钳,從而防止某些錯誤的產(chǎn)生钦铁。
2. 箭頭函數(shù)
在 ES6 中箭頭函數(shù)是其最有趣的新增特性,它是一種使用箭頭=>
定義函數(shù)的新語法蹋嵌,和傳統(tǒng)函數(shù)的不同主要集中在:
- 沒有
this
育瓜、super
、arguments
和new.target
綁定 - 不能通過
new
關鍵字調用 - 沒有原型
- 不可以改變
this
的綁定 - 不支持
arguments
對象 - 不支持重復的命名參數(shù)
this
的綁定是JS程序中一個常見的錯誤來源栽烂,尤其是在函數(shù)內(nèi)就很容易對this
的值是去控制躏仇,經(jīng)常會導致意想不到的行為。
在出現(xiàn)箭頭函數(shù)之前腺办,在聲明構造函數(shù)并且修改原型的時候焰手,經(jīng)常會需要對this
的值進行很多處理:
function Phone() {
this.type = type
}
Phone.prototype.fixTips = function(tips) {
// var that = this
return tips.map(function(tip) {
// return that.type + tip
return this.type + tip
// })
},this)
}
要輸出正確的fixTips
,必須要對this
的指向存在變量中或者給它找個上下文綁定怀喉,而如果使用箭頭函數(shù)的話书妻,則很容易實現(xiàn):
function Phone() {
this.type = type
}
Phone.prototype.fixTips = function(tips) {
return tips.map(tip => this.type + tip)
}
就像上面的例子一樣,在我們寫一個函數(shù)的時候躬拢,箭頭函數(shù)更加簡潔并且可以簡單地返回一個值躲履。
當我們需要維護一個
this
上下文的時候,就可以使用箭頭函數(shù)聊闯。
3. 字符串
我認為 ES6 在對字符串處理這一塊工猜,新增的特性是最多的,本文只總結常用的方法菱蔬,但還是推薦大家有時間去仔細了解一下篷帅。
.includes()
之前在需要判斷字符串中是否包含某些字符串的時候,基本都是通過indexOf()
的返回值來判斷的:
var str = 'superman'
var subStr = 'super'
console.log(str.indexOf(subStr) > -1)
// true
而現(xiàn)在可以簡單地使用includes()
來進行判斷拴泌,會返回一個布爾值:
const str = 'superman'
const subStr = 'super'
console.log(str.includes(subStr))
// true
當然除此之外還有兩個特殊的方法魏身,它們的用法和includes()
一樣:
- startWith():如果在字符串的起始部分檢測到指定文本則返回
true
- endsWith():如果在字符串的結束部分檢測到指定文本則返回
true
.repeat()
在此之前,需要重復字符串蚪腐,我們需要自己封裝一個函數(shù):
function repeat(str, count) {
var strs = []
while(str.length < count) {
strs.push(str)
}
return strs.join('')
}
現(xiàn)在則只需要調用repeat()
就可以了:
'superman'.repeat(2)
// supermansuperman
模板字符串
我覺得模板字符串也是ES6最牛逼的特性之一箭昵,因為它極大地簡化了我們對于字符串的處理,開發(fā)過程中也是用得特別爽回季。
首先它讓我們不用進行轉義處理了:
var text = 'my name is \'Branson\'.'
const newText = `my name is 'Branson'.`
然后它還支持插入宙枷、換行和表達式:
const name = 'Branson'
console.log(`my name is ${name}.`)
// my name is Branson.
const text = (`
what's
wrong
?
`)
console.log(text)
// what's
// wrong
// ?
const today = new Date()
const anotherText = `The time and date is ${today.toLocaleString()}.`
console.log(anotherText)
// The time and date is 2017-10-23 14:52:00
值得注意的是掉房,之前在改離職同學留下的bug時茧跋,也發(fā)現(xiàn)了要推薦使用模板字符串的一個點:
formatDate(date) {
if(!date) return ""
if(!(date instanceof Date)) date = new Date(date)
const y = date.getFullYear()
let m = date.getMonth() + 1
m = m < 10 ? ('0' + m) : m
let d = date.getDate()
d = d < 10 ? ('0' + d) : d
// return y + m + d
return `${y}${m}$e6saq6q`
}
之前使用的是注釋掉的輸出方式慰丛,由于這位同學在判斷m
和d
的值的時候,沒有把大于10情況下的值類型轉換成字符串瘾杭,所以在我們放了個“十一”假回來輸出的值就出現(xiàn)問題了诅病。
而使用模板字符串有一個好處就是,我不管你m
和d
是不是類型轉換了粥烁,我最后都輸出一個字符串贤笆,算是容錯率更高了吧。
4. 解構
解構可以讓我們用一個更簡便的語法從一個數(shù)組或者對象(即使是深層的)中分離出來值讨阻,并存儲他們芥永。
這一塊沒什么可說的,直接放代碼了:
// 數(shù)組解構
// ES5
var arr = [1, 2, 3, 4]
var a = arr[0]
var b = arr[1]
var c = arr[2]
var d = arr[3]
// ES6
let [a, b, c, d] = [1, 2, 3, 4]
// 對象解構
// ES5
var luke = {occupation: 'jedi', father: 'anakin'}
var occupation = luke.occupation
// 'jedi'
var father = luke.father
// 'anakin'
// ES6
let luke = {occupation: 'jedi', father: 'anakin'}
let {occupation, father} = luke
console.log(occupation)
// 'jedi'
console.log(father)
// 'anakin'
5. 模塊
在 ES6 之前钝吮,我們使用Browserify
這樣的庫來創(chuàng)建客戶端的模塊化埋涧,在node.js
中使用require
。在 ES6 中奇瘦,我們可以直接使用所有類型的模塊化(AMD 和 CommonJS)棘催。
CommonJS 模塊的出口定義:
module.exports = 1
module.exports = { foo: 'bar' }
module.exports = ['foo', 'bar']
module.exports = function bar () {}
ES6 模塊的出口定義:
// 暴露單個對象
export let type = 'ios'
// 暴露多個對象
function deDuplication(arr) {
return [...(new Set(arr))]
}
function fix(item) {
return `${item} ok!`
}
export {deDuplication, fix}
// 暴露函數(shù)
export function sumThree(a, b, c) {
return a + b + c
}
// 綁定默認輸出
let api = {
deDuplication,
fix
}
export default api
// export { api as default }
模塊出口最佳實踐:總是在模塊的最后面使用
export default
方法,這可以讓暴露的東西更加清晰并且可以節(jié)省時間去找出暴露出來值的名字耳标。尤其如此醇坝,在 CommonJS 中通常的實踐就是暴露一個簡單的值或者對象。堅持這種模式次坡,可以讓我們的代碼更加可讀呼猪,并且在 ES6 和 CommonJS 模塊之間更好地兼容。
ES6 模塊導入:
// 導入整個文件
import 'test'
// 整體加載
import * as test from 'test'
// 按需導入
import { deDuplication, fix } from 'test'
// 遇到出口為 export { foo as default, foo1, foo2 }
import foo, { foo1, foo2 } from 'foos'
6. 參數(shù)
參數(shù)這一塊兒在這之前砸琅,無論是默認參數(shù)宋距、不定參數(shù)還是重命名參數(shù)都需要我們做很多處理,有了ES6之后相對來說就簡潔多了:
默認參數(shù):
// ES5
function add(x, y) {
x = x || 0
y = y || 0
return x + y
}
// ES6
function add(x=0, y=0) {
return x + y
}
add(3, 6) // 9
add(3) // 3
add() // 0
不定參數(shù):
// ES5
function logArgs() {
for(var i = 0; i < arguments.length; i++) {
console.log(arguments[i])
}
}
// ES6
function logArgs(...args) {
for(let arg of args) {
console.log(arg)
}
}
命名參數(shù):
// ES5
function Phone(options) {
var type = options.type || 'ios'
var height = options.height || 667
var width = options.width || 375
}
// ES6
function Phone(
{type='ios', height=667, width=375}) {
console.log(height)
}
展開操作:
求一個數(shù)組的最大值:
// ES5
Math.max.apply(null, [-1, 100, 9001, -32])
// ES6
Math.max(...[-1, 100, 9001, -32])
當然這個特性還可以用來進行數(shù)組的合并:
const player = ['Bryant', 'Durant']
const team = ['Wade', ...player, 'Paul']
console.log(team)
// ['Wade', 'Bryant', 'Durant', 'Paul']
7. 類 class
關于面向對象這個詞明棍,大家都不陌生乡革,在這之前,JS要實現(xiàn)面向對象編程都是基于原型鏈摊腋,ES6提供了很多類的語法糖沸版,我們可以通過這些語法糖,在代碼上簡化很多對prototype
的操作:
// ES5
// 創(chuàng)造一個類
function Animal(name, age) {
this.name = name
this.age = age
}
Animal.prototype.incrementAge = function() {
this.age += 1
}
// 類繼承
function Human(name, age, hobby, occupation) {
Animal.call(this, name, age)
this. hobby = hobby
this.occupation = occupation
}
Human.prototype = Object.create(Animal.prototype)
Human.prototype.constructor = Human
Human.prototype.incrementAge = function() {
Animal.prototype.incrementAge.call(this)
console.log(this.age)
}
在ES6中使用語法糖簡化:
// ES6
// 創(chuàng)建一個類
class Animal {
constructor(name, age) {
this.name = name
this.age = age
}
incrementAge() {
this.age += 1
}
}
// 類繼承
class Human extends Animal {
constructor(name, age, hobby, occupation) {
super(name, age)
this.hobby = hobby
this.occupation = occupation
}
incrementAge() {
super.incrementAge()
console.log(this.age)
}
}
注意:盡管類與自定義類型之間有諸多相似之處兴蒸,我們?nèi)匀恍枰斡浰鼈冎g的這些差異:
- 函數(shù)聲明可以被提升视粮,而類聲明與
let
聲明類似,不能被提升橙凳;真正執(zhí)行聲明語句之前蕾殴,它們會一直存在于臨時死區(qū)中笑撞。 - 類聲明中的所有代碼將自動運行在嚴格模式下,而且無法強行讓代碼脫離嚴格模式進行钓觉。
- 在自定義類型中茴肥,需要通過
Object.defineProperty()
方法手動指定某個方法不可枚舉;而在類中荡灾,所有方法都是不可枚舉的瓤狐。 - 每個類都有一個
constructor
方法,通過關鍵字new
調用那些不包含constructor
的方法會導致程序拋出錯誤批幌。 - 使用除關鍵字
new
以外的方式調用類的構造函數(shù)會導致程序拋出錯誤础锐。 - 在類中修改類名會導致程序報錯。
8. Symbols
Symbols
在 ES6 之前就已經(jīng)存在荧缘,我們現(xiàn)在可以直接使用一個開發(fā)的接口了皆警。
Symbols
是不可改變并且是獨一無二的,可以在任意哈希中作一個key截粗。
Symbol():
調用Symbol()
或者Symbol(description)
可以創(chuàng)造一個獨一無二的符號信姓,但是在全局是看不到的。Symbol()
的一個使用情況是給一個類或者命名空間打上補丁桐愉,但是可以確定的是你不會去更新它财破。比如,你想給React.Component
類添加一個refreshComponent
方法从诲,但是可以確定的是你不會在之后更新這個方法:
const refreshComponent = Symbol()
React.Component.prototype[refreshComponent] = () => {
// do something
}
Symbol.for(key):
Symbol.for(key)
同樣會創(chuàng)造一個獨一無二并且不可改變的 Symbol左痢,但是它可以全局看到,兩個相同的調用Symbol.for(key)
會返回同一個Symbol
類:
Symbol('foo') === Symbol('foo')
// false
Symbol.for('foo') === Symbol('foo')
// false
Symbol.for('foo') === Symbol.for('foo')
// true
對于 Symbols 的普遍用法(尤其是Symbol.for(key)
)是為了協(xié)同性系洛。它可以通過在一個第三方插件中已知的接口中對象中的參數(shù)中尋找用 Symbol 成員來實現(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')
}
}
在另一個庫中:
const specialRead = Symbol.for('specialRead')
class SomeReadableType {
[specialRead]() {
const reader = createSomeReaderFrom(this)
return reader
}
}
9. Set/Map
在此之前,開發(fā)者都是用對象屬性來模擬set
和map
兩種集合:
// set
var set = Object.create(null)
set.foo = true
if(set.foo) {
// do something
}
// map
var map = Object.create(null)
map.foo = 'bar'
var value = map.foo
console.log(value)
// 'bar'
由于在 ES6 中set
和map
的操作與其它語言類似描扯,本文就不過多介紹這些定页,主要通過幾個例子來說說它們的應用。
在 ES6 中新增了有序列表set
绽诚,其中含有一些相互獨立的非重復值典徊,通過set
集合可以快速訪問其中的數(shù)據(jù),更有效地追蹤各種離散值恩够。
關于set
運用得最多的應該就是去重了:
const arr = [1, 1, 2, 11, 32, 1, 2, 3, 11]
const deDuplication = function(arr) {
return [...(new Set(arr))]
}
console.log(deDuplication(arr))
// [1, 2, 11, 32, 3]
map
是一個非常必需的數(shù)據(jù)結構卒落,在 ES6 之前,我們通過對象來實現(xiàn)哈希表:
var map = new Object()
map[key1] = 'value1'
map[key2] = 'value2'
但是它并不能防止我們偶然地用一些特殊的屬性名重寫函數(shù):
getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned')
// TypeError: Property 'hasOwnProperty' is not a function
在 ES6 中map
允許我們隊值進行get
蜂桶、set
和search
操作:
let map = new Map()
map.set('name', 'david')
map.get('name')
// david
map.has('name')
// true
而map
更令人驚奇的部分就是它不僅限于使用字符串作為 key儡毕,還可以用其他任何類型的數(shù)據(jù)作為 key:
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
注意:我們使用map.get()
方法去測試相等時,如果在map
中使用函數(shù)或者對象等非原始類型值的時候測試將不起作用扑媚,所以我們應該使用 Strings, Booleans 和 Numbers 這樣的原始類型的值腰湾。
我們還可以使用 .entries()
來遍歷迭代:
for(let [key, value] of map.entries()) {
console.log(key, value);
}
10. Weak Set/Weak Map
對于set
和WeakSet
來說雷恃,它們之間最大的區(qū)別就是,WeakSet
保存的是對象值得弱引用费坊,下面這個實例會展示它們的差異:
let set = new WeakSet(),
key = {}
set.add(key)
console.log(set.has(key))
// true
// 移除對象key的最后一個強引用( WeakSet 中的引用也自動移除 )
key = null
這段代碼執(zhí)行過后倒槐,就無法訪問WeakSet
中 key 的引用了。除了這個葵萎,它們還有以下幾個差別:
- 在
WeakSet
的實例中导犹,如果向add()
、has()
和delete()
這三個方法傳入非對象參數(shù)都會導致程序報錯羡忘。 -
WeakSet
集合不可迭代,所以不能被用于for-of
循環(huán)磕昼。 -
WeakSet
集合不暴露任何迭代器(例如keys()
和values()
方法)卷雕,所以無法通過程序本身來檢測其中的內(nèi)容。 -
WeakSet
集合不支持forEach()
方法票从。 -
WeakSet
集合不支持size
屬性漫雕。
總之,如果你只需要跟蹤對象引用峰鄙,你更應該使用WeakSet
集合而不是普通的set
集合浸间。
在 ES6 之前,為了存儲私有變量吟榴,我們有各種各樣的方法去實現(xiàn)魁蒜,其中一種方法就是用命名約定:
class Person {
constructor(age) {
this._age = age
}
_incrementAge() {
this._age += 1
}
}
但是命名約定在代碼中仍然會令人混淆并且并不會真正的保持私有變量不被訪問。現(xiàn)在吩翻,我們可以使用WeakMap
來存儲變量:
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
存儲變量很酷的一件事是它的 key 他不需要屬性名稱兜看,可以使用Reflect.ownKeys()
來查看這一點:
const person = new Person(50)
person.incrementAge()
// 'Midlife crisis'
Reflect.ownKeys(person)
// []
一個更實際的實踐就是可以WeakMap
儲存 DOM 元素,而不會污染元素本身:
let map = new WeakMap()
let el = document.getElementById('someElement');
// Store a weak reference to the element with a key
map.set(el, 'reference')
// Access the value of the element
let value = map.get(el)
// 'reference'
// Remove the reference
el.parentNode.removeChild(el)
el = null
如上所示狭瞎,當一個對象被垃圾回收機制銷毀的時候细移,WeakMap
將會自動地一處關于這個對象地鍵值對。
注意:為了進一步說明這個例子的實用性熊锭,可以考慮 jQuery 是如何實現(xiàn)緩存一個對象相關于對引用地 DOM 元素對象弧轧。使用 jQuery ,當一個特定地元素一旦在 document 中移除的時候碗殷,jQuery 會自動地釋放內(nèi)存精绎。總體來說亿扁,jQuery 在任何 dom 庫中都是很有用的捺典。
11. Promise
在 ES6 出現(xiàn)之前,處理異步函數(shù)主要是通過回調函數(shù)从祝,雖然看起來也挺不錯襟己,但是用多之后就會發(fā)現(xiàn)嵌套太多回調函數(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
})
})
})
})
})
當我們有了 Promise 之后引谜,就可以將這些轉化成垂直代碼:
func1(value1)
.then(func2)
.then(func3)
.then(func4)
.then(func5, value5 => {
// Do something with value 5
})
原生的 Promise 有兩個處理器:resolve
(當 Promise 是fulfilled
時的回調)和reject
(當 Promise 是rejected
時的回調):
new Promise((resolve, reject) =>
reject(new Error('Failed to fulfill Promise')))
.catch(reason => console.log(reason))
Promise的好處:對錯誤的處理使用一些列回調會使代碼很混亂,使用 Promise擎浴,我看可以清晰的讓錯誤冒泡并且在合適的時候處理它员咽,甚至,在 Promise 確定了resolved/rejected
之后贮预,他的值是不可改變的——它從來不會變化贝室。
這是使用 Promise 的一個實際的例子:
const request = require('request')
return new Promise((resolve, reject) => {
request.get(url, (error, response, body) => {
if (body) {
resolve(JSON.parse(body))
} else {
resolve({})
}
})
})
我們還可以使用 Promise.all()
來并行處理多個異步函數(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
})
12. Generators 生成器
就像 Promise 可以幫我們避免回調地獄,Generator 可以幫助我們讓代碼風格更整潔——用同步的代碼風格來寫異步代碼仿吞,它本質上是一個可以暫停計算并且可以隨后返回表達式的值的函數(shù):
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
可以回去到下一個yield
返回的值滑频,當然上面的代碼是非常不自然的,我們可以利用 Generator 來用同步的方式來寫異步操作:
function request(url) {
getJSON(url, function(response) {
generator.next(response)
})
}
這里的 generator 函數(shù)將會返回需要的數(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
有data1
中我們需要解析并儲存的數(shù)據(jù)峡迷。
雖然我們可以利用 Generator 來用同步的方式來寫異步操作,但是確認錯誤的傳播變得不再清晰你虹,我們可以在 Generator 中加上 Promise:
function request(url) {
return new Promise((resolve, reject) => {
getJSON(url, resolve)
})
}
然后我們寫一個函數(shù)逐步調用next
并且利用 request 方法產(chǎn)生一個 Promise:
function iterateGenerator(gen) {
var generator = gen()
(function iterate(val) {
var ret = generator.next()
if(!ret.done) {
ret.value.then(iterate)
}
})()
}
在 Generators 中加上 Promise 之后我們可以更清晰的使用 Promise 中的.catch
和reject
來捕捉錯誤绘搞,讓我們使用新的 Generator,和之前的還是蠻相似的:
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)
})
13. Async Await
當 ES7 真正到來的時候傅物,async await
可以用更少的處理實現(xiàn) Promise 和 Generators 所實現(xiàn)的異步處理:
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()
14. Getter/Setter 函數(shù)
ES6 已經(jīng)開始實現(xiàn)了 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")
// uses the get method in the background
if (emp.name) {
console.log(emp.name)
// Mr. JAMES BOND
}
// uses the setter in the background
emp.name = "Bond 007"
console.log(emp.name)
// Mr. BOND 007
最新版本的瀏覽器也在對象中實現(xiàn)了getter
和setter
函數(shù)夯辖,我們可以使用它們來實現(xiàn) 計算屬性,在設置和獲取一個屬性之前加上監(jiān)聽器和處理董饰。
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
總結
本文部分代碼參考自:https://github.com/DrkSephy/es6-cheatsheet
主要是為了分享一些 ES6 的用法技巧以及最佳實踐蒿褂,歡迎交流!