ES6 總結(一):常用方法

Tip

最近讀完了 Nicholas C. Zakas 的新書 深入理解ES6跷敬,根據(jù)之前的經(jīng)驗和一些文檔梳理的知識脈絡麻车,總結一些關于 ES6 的常用方法和技巧。

本文參考文章:https://github.com/DrkSephy/es6-cheatsheet

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

而在引入letconst之后冀值,這兩個關鍵字會自動生成代碼塊也物,并且不存在變量提升,因此只需要把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

關鍵字letconst的區(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育瓜、superargumentsnew.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`
}

之前使用的是注釋掉的輸出方式慰丛,由于這位同學在判斷md的值的時候,沒有把大于10情況下的值類型轉換成字符串瘾杭,所以在我們放了個“十一”假回來輸出的值就出現(xiàn)問題了诅病。
而使用模板字符串有一個好處就是,我不管你md是不是類型轉換了粥烁,我最后都輸出一個字符串贤笆,算是容錯率更高了吧。

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ā)者都是用對象屬性來模擬setmap兩種集合:

// 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 中setmap的操作與其它語言類似描扯,本文就不過多介紹這些定页,主要通過幾個例子來說說它們的應用。

在 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蜂桶、setsearch操作:

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

對于setWeakSet來說雷恃,它們之間最大的區(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(當 Promisefulfilled時的回調)和reject(當 Promiserejected時的回調):

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唤冈,我們可以保證entry1data1中我們需要解析并儲存的數(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 中的.catchreject來捕捉錯誤绘搞,讓我們使用新的 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) PromiseGenerators 所實現(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)了 gettersetter 函數(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)了gettersetter函數(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 的用法技巧以及最佳實踐蒿褂,歡迎交流!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尖阔,一起剝皮案震驚了整個濱河市贮缅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌介却,老刑警劉巖谴供,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異齿坷,居然都是意外死亡桂肌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門永淌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崎场,“玉大人,你說我怎么就攤上這事遂蛀√房纾” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長螃宙。 經(jīng)常有香客問我蛮瞄,道長,這世上最難降的妖魔是什么谆扎? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任挂捅,我火速辦了婚禮,結果婚禮上堂湖,老公的妹妹穿的比我還像新娘闲先。我一直安慰自己,他們只是感情好无蜂,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布伺糠。 她就那樣靜靜地躺著,像睡著了一般酱讶。 火紅的嫁衣襯著肌膚如雪退盯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天泻肯,我揣著相機與錄音,去河邊找鬼慰照。 笑死灶挟,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的毒租。 我是一名探鬼主播稚铣,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼墅垮!你這毒婦竟也來了惕医?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤算色,失蹤者是張志新(化名)和其女友劉穎抬伺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灾梦,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡峡钓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了若河。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片能岩。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖萧福,靈堂內(nèi)的尸體忽然破棺而出拉鹃,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布膏燕,位于F島的核電站钥屈,受9級特大地震影響,放射性物質發(fā)生泄漏煌寇。R本人自食惡果不足惜焕蹄,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阀溶。 院中可真熱鬧腻脏,春花似錦、人聲如沸银锻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽击纬。三九已至鼎姐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間更振,已是汗流浹背炕桨。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留肯腕,地道東北人献宫。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像实撒,于是被迫代替她去往敵國和親姊途。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 異步編程對JavaScript語言太重要知态。Javascript語言的執(zhí)行環(huán)境是“單線程”的捷兰,如果沒有異步編程,根本...
    呼呼哥閱讀 7,309評論 5 22
  • 下面不屬于ECMAScript規(guī)范的范圍的是:( )A负敏、 數(shù)據(jù)類型B贡茅、 語法C、 DOM事件D原在、 內(nèi)置對象和函數(shù)的...
    亓凡閱讀 2,973評論 3 9
  • 以下內(nèi)容是我在學習和研究ES6時友扰,對ES6的特性、重點和注意事項的提取庶柿、精練和總結村怪,可以做為ES6特性的字典;在本...
    科研者閱讀 3,126評論 2 9
  • 1.概述 ES5的對象屬性名都是字符串浮庐,這容易造成屬性名的沖突甚负。比如柬焕,你使用了一個他人提供的對象,但又想為這個對象...
    趙然228閱讀 808評論 2 10
  • 有個剛畢業(yè)的校友富玷,95年的小妹妹問我:格總,我現(xiàn)在也不知道該干啥既穆,你有沒有什么建議笆昱场? 當然有幻工,如果你年紀輕輕不知...
    格總閱讀 1,002評論 19 17