ES6 新特性學(xué)習(xí)

概覽

ES6,全稱ECMAScript 6.0,是JavaScript的下一版本標(biāo)準(zhǔn),2015.06發(fā)布。

ES6主要是為了解決ES5的先天不足,比如JavaScript里沒有類的概念、內(nèi)置集合對(duì)象Map和Set、迭代器、異步編程等。

特性

1 聲明與表達(dá)式

1.1 let 與 const

let 和 const 是在ES6中新增的兩個(gè)關(guān)鍵字。

let聲明的變量只在let命令所在的代碼塊內(nèi)有效,不能重復(fù)聲明, 不存在變量提升。

var 定義的變量是在全局范圍內(nèi)有效,可以重復(fù)聲明,存在變量提升。

{
    console.log(a)   // ReferenceError: Cannot access 'a' before initialization
    let a = 0 
    console.log(a)   // 0
    let a = 1  // SyntaxError: Identifier 'a' has already been declared
}
console.log(a)  // ReferenceError: a is not defined

const聲明一個(gè)只讀的常量,一旦聲明,常量的值就不能改變。意味著一旦聲明就必須初始化,否則會(huì)報(bào)錯(cuò)。

const PI = "3.1415926";
console.log(PI)  // 3.1415926
const MY_AGE;  // SyntaxError: Missing initializer in const declaration    

const 保證的不是變量的值不變,而是保證變量所指向的內(nèi)存地址所保存的數(shù)據(jù)不允許改動(dòng)。

1.2 解構(gòu)賦值

解構(gòu)賦值是對(duì)賦值運(yùn)算符的擴(kuò)展,是一種針對(duì)數(shù)組或者對(duì)象進(jìn)行模式匹配,然后對(duì)其中的變量進(jìn)行賦值。在代碼書寫上簡潔且易讀,語義更加清晰明了;也方便了復(fù)雜對(duì)象中數(shù)據(jù)字段的獲取。

數(shù)組模型解構(gòu)(Array)
  • 基本
let [a,b,c] = [1,2,3]
console.log(a)  // 1
console.log(b)  // 2
console.log(c)  // 3
  • 可嵌套
let [a,[[b],c]] = [1,[[2],3]]
  • 可忽略
let [a, ,b] = [1,2,3]
  • 不完全解構(gòu)
let [a = 1, b] = []
console.log(a)  // a = 1
console.log(b)  // b = undefined
  • 剩余運(yùn)算符
let [a, ...b] = [1,2,3]
console.log(a)  // a = 1
console.log(b)  // b = [2,3]
  • 字符串等
let [a,b,c,d,e] = 'hello'
console.log(a)  // a = 'h'
console.log(b)  // a = 'e'
console.log(c)  // a = 'l'
console.log(d)  // a = 'l'
console.log(e)  // a = 'o'
  • 解構(gòu)默認(rèn)值
let [a = 2] = [undefined]
console.log(a)  // a = 2

當(dāng)解構(gòu)模式有匹配結(jié)果,且匹配結(jié)果是undefined時(shí),會(huì)觸發(fā)默認(rèn)值作為返回值

let [a = 3, b = a] = [];     // a = 3, b = 3
let [a = 3, b = a] = [1];    // a = 1, b = 1
let [a = 3, b = a] = [1, 2]; // a = 1, b = 2
對(duì)象模型解構(gòu)(Object)
  • 基本
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }
console.log(foo)  //  foo = 'aaa'
console.log(bar)  //  bar = 'bbb'

其它可參考數(shù)組模型的解構(gòu)

1.3 Symbol

ES6引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨(dú)一無二的值,最大的用法是用來定義對(duì)象的唯一屬性名。

  • 基本用法
let sy = Symbol('kk')
console.log(sy)    // Symbol(kk)
typeof(sy)         // 'symbol'

//相同參數(shù) Symbol() 返回的值不相等
let sy1 = Symbol('kk')
sy === sy1        // false
  • 注意事項(xiàng)
  • Symbol 作為對(duì)象屬性名時(shí)不能用.運(yùn)算符,要用方括號(hào)。因?yàn)?運(yùn)算符后面是字符串,所以取到的是字符串 sy 屬性,而不是 Symbol 值 sy 屬性。
  • Symbol 值作為屬性名時(shí),該屬性是公有屬性不是私有屬性,可以在類的外部訪問
  • 不會(huì)出現(xiàn)在 for...in 、 for...of 的循環(huán)中,也不會(huì)被 Object.keys() 、 Object.getOwnPropertyNames() 返回
  • 要讀取到一個(gè)對(duì)象的 Symbol 屬性,可以通過 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到
  • Symbol.for()

類似單例模式,首先會(huì)在全局搜索被登記的 Symbol 中是否有該字符串參數(shù)作為名稱的 Symbol 值,如果有即返回該 Symbol 值,若沒有則新建并返回一個(gè)以該字符串參數(shù)為名稱的 Symbol 值,并登記在全局環(huán)境中供搜索。

let yellow = Symbol("Yellow");
let yellow1 = Symbol.for("Yellow");
yellow === yellow1;      // false
 
let yellow2 = Symbol.for("Yellow");
yellow1 === yellow2;     // true
  • Symbol.keyFor()

Symbol.keyFor() 返回一個(gè)已登記的 Symbol 類型值的 key ,用來檢測(cè)該字符串參數(shù)作為名稱的 Symbol 值是否已被登記。

let yellow1 = Symbol.for("Yellow");
Symbol.keyFor(yellow1);    // "Yellow"

2 內(nèi)置對(duì)象

2.1 Map 與 Set

Map

Map 對(duì)象保存鍵值對(duì)。任何值(對(duì)象或者原始值)都可以作為一個(gè)鍵或者一個(gè)值。

Maps 和 Objects 的區(qū)別:

  • 一個(gè)Object的鍵只能是字符串或者是Symbol, 但一個(gè)Map的鍵可以是任意值。
  • Map中的鍵值是有序的(FIFO原則),而添加到對(duì)象中的鍵值則不是。
  • Map中的鍵值對(duì)個(gè)數(shù)可以從size屬性獲取,而Object的鍵值對(duì)個(gè)數(shù)只能手動(dòng)計(jì)算。
  • Object都有自己的原型,原型鏈上的鍵名有可能和你自己在對(duì)象上設(shè)置的鍵名產(chǎn)生沖突。
  • 基本使用

    let myMap = new Map()
    myMap.set('key','value')   // key is string
    myMap.get('key')           // value
    myMap.set(NaN, 'not a number')  // key is NaN
    
  • Map的迭代

    for ... of

    let myMap = new Map()
    myMap.set(0, 'zero')
    myMap.set(1, 'one')
    
    for(let [key,value] of myMap){
        console.log(key + ' = ' + value)
    }
    

    forEach()

    myMap.forEach(function(key,value){
        console.log(key + ' = ' + value)
    })
    
  • Map對(duì)象的操作

    Map 與 Array 的轉(zhuǎn)換

    let vkArr = [['key1','value1'],['key2','value2']]
    let myMap = new Map(vkArr)      // 將一個(gè)二維數(shù)組轉(zhuǎn)換成 Map 對(duì)象
    let outArr = Array.from(myMap)  // 將一個(gè)Map 轉(zhuǎn)換成 Array
    

    Map 的克隆

    let originalMap = new Map([['key1','value1'],['key2','value2']])
    let cloneMap = new Map(originalMap)
    console.log(originalMap === cloneMap)  // false, Map對(duì)象構(gòu)造函數(shù)生成實(shí)例,迭代出新的對(duì)象
    

    Map 的合并

    let first = new Map([[1, 'one'], [2, 'two'], [3, 'three'],])
    let second = new Map([[1, 'uno'], [2, 'dos']])
    let merged = new Map(...first, ...second)  //合并Map對(duì)象時(shí),如果鍵值重復(fù),則后面的覆蓋前面的
    
Set

Set對(duì)象允許你存儲(chǔ)任何類型的唯一值,無論是原始值或者是對(duì)象引用。

Set對(duì)象存儲(chǔ)的值總是唯一的,所以需要判斷兩個(gè)值是否恒等。有幾個(gè)特殊值需要注意:

  • +0 與 -0 在存儲(chǔ)判斷唯一性的時(shí)候是恒等的,所以不重復(fù);
  • undefined 與 undefined 是恒等的,所以不重復(fù);
  • NaN 與 NaN 是不恒等的,但是在Set中只能存一個(gè),不重復(fù);
  • 基本使用

    let mySet = new Set()
    mySet.add(1)
    mySet.add(5)
    mySet.add('string')
    
  • 類型轉(zhuǎn)換

    let mySet = new Set(['value1','value2','value3'])     // Array 轉(zhuǎn) Set
    let myArray = [...mySet]    // 用 ...操作符 將Set 轉(zhuǎn) Array 
    //string 轉(zhuǎn) set
    let mySet = new Set('hello')  // Set(4) {'h','e','l','l','o'}
    
  • Set 對(duì)象作用

    //數(shù)組去重
    let mySet = new Set([1,2,3,4,4])
    [...mySet]  //[1,2,3,4]
    //并集
    let a = new Set([1,2,3])
    let b = new Set([4,3,2])
    let union = new Set([...a, ...b]) // Set(4) {1,2,3,4}
    //交集
    let intersect = new Set([...a].filter(x => b.has(x)))  // Set(2) {2,3}
    //差集
    let difference = new Set([...a].filter(x => !b.has(x)))  // {1}
    

2.2 Proxy 與 Reflect

Proxy(代理)

Proxy 可以對(duì)目標(biāo)對(duì)象的讀取、函數(shù)調(diào)用等操作進(jìn)行攔截,然后進(jìn)行操作處理。它不直接操作對(duì)象,而是像代理模式,通過對(duì)象的代理對(duì)象進(jìn)行操作,在進(jìn)行這些操作時(shí),可以添加一些額外的操作。‘

  • 基本用法

    let target = {
        name: 'Tom',
        age: 24
    }
    let handler = {
        get: function(target, key) {
            console.log('getting ' + key);
            return target[key]; // 不是target.key
        },
        set: function(target, key, value) {
            console.log('setting ' + key);
            target[key] = value;
        }
    }
    let proxy = new Proxy(target, handler)
    proxy.name     // 實(shí)際執(zhí)行 handler.get
    proxy.age = 25 // 實(shí)際執(zhí)行 handler.set
    
Reflect(映射)

Reflect 可以用于獲取目標(biāo)對(duì)象的行為,與Object類似,但是更易讀,為操作對(duì)象提供了一個(gè)種更優(yōu)雅的方式。它的方法與Proxy是對(duì)應(yīng)的。

let exam = {
    name: "Tom",
    age: 24,
    get info(){
        return this.name + this.age;
    }
}
Reflect.get(exam, 'name'); // "Tom"
Reflect.set(exam, 'age', 25); // true
組合使用

Reflect 對(duì)象的方法與Proxy對(duì)象的方法是一一對(duì)應(yīng)的,所以Proxy對(duì)象的方法可以通過調(diào)用Reflect對(duì)象的方法獲取默認(rèn)行為,然后進(jìn)行額外操作。

    let target = {
        name: 'Tom',
        age: 24
    }
    let handler = {
        get: function (target, key) {
            console.log('getting ' + key);
            // return target[key];
            return Reflect.get(target,key);
        },
        set: function (target, key, value) {
            console.log('setting ' + key + ' value: ' + value);
            // target[key] = value;
            Reflect.set(target,key,value);
        }
    }
    let proxy = new Proxy(target,handler)
    proxy.age = 33
    console.log('name is '+ proxy.name)

2.3 字符串

擴(kuò)展的方法
方法名 方法描述 示例
includes() 返回boolean,判斷是否找到參數(shù)字符串 'hello'.includes('llo') // true
startsWith() 返回boolean,判斷參數(shù)字符串是否在原字符串的頭部 'hello'.startsWith('he') // true
endsWith() 返回boolean,判斷參數(shù)字符串是否在原字符串的尾部 'hello'.endsWith('o') //true
indexOf() 返回字串的位置 'hello'.indexOf('h') // 0
lastIndexOf() 返回字串最后出現(xiàn)的位置 'hello'.lastIndexOf('h') // 4
repeat() 返回新字符串,表示將字符串重復(fù)指定次數(shù) 'hello,'.repeat(2) // 'hello,hello,'
padStart() 返回新字符串,用參數(shù)字符從頭部(左側(cè))補(bǔ)全字符串 'h'.padStart(5,'o') // 'ooooh'
padEnd() 返回新字符串,用參數(shù)字符從尾部(右側(cè))補(bǔ)全字符串 'h'.padEnd(5,'o') // 'hoooo'
模板字符串

模板字符串相當(dāng)于加強(qiáng)版的字符串,用反引號(hào)`,除了作為普通字符串,還可以用來定義多行字符串,還可以在字符串中加入變量和表達(dá)式。

let name = 'Mike'
let age = 24
let info = `My name is ${name}, I am ${age + 1} years old next year.`

2.4 數(shù)值

N/A

2.5 對(duì)象

對(duì)象字面量
  • 屬性的簡潔表示法。允許對(duì)象的屬性直接寫變量,這時(shí)候?qū)傩悦褪亲兞棵?,屬性值就是變量值?/p>

    const age = 12
    const name = 'Amy'
    const person = {age, name}
    console.log(person)  // {age: 12, name: 'Amy'}
    
  • 方法名也可以簡寫

    const person = {
        sayHi(){ console.log('Hi')}
    }
    //等同于
    const person = {
        sayHi: function(){ console.log('Hi')}
    }
    
  • 屬性名表達(dá)式

    const obj = {
        ['hel' + 'lo']() { return 'Hi'}
    }
    obj.hello()
    

    注意:屬性的簡潔表示法和屬性名表達(dá)式不能同時(shí)使用,否則會(huì)報(bào)錯(cuò)

對(duì)象的拓展運(yùn)算符

拓展運(yùn)算符 (...) 用于取出參數(shù)對(duì)象所有可遍歷屬性然后拷貝到當(dāng)前對(duì)象

  • 基本用法

    let person = {name: 'Amy', age: 12}
    let someone = {...person}
    console.log(someone)  // {name: 'Amy', age: 12}
    
  • 用于合并兩個(gè)對(duì)象

    let age = {age: 12}
    let name = {name: 'Amy'}
    let person = {...age, ...name}
    

    自定義的屬性和拓展運(yùn)算符對(duì)象里面屬性相同的時(shí)候,自定義的屬性在拓展運(yùn)算符后面,則拓展運(yùn)算符對(duì)象內(nèi)部同名的屬性將被覆蓋掉。

對(duì)象的新方法
  • Object.assign(target, source, ...)

    用于將源對(duì)象的所有可枚舉屬性復(fù)制到目標(biāo)對(duì)象中。

    let target = {a: 1}
    let obj1 = {b: 2}
    let obj2 = {c: 3}
    Object.assign(target,obj1, obj2)
    console.log(target)  // {a:1, b:2, c:3}
    

    a. 如果目標(biāo)對(duì)象和源對(duì)象有同名屬性,或者多個(gè)源對(duì)象有同名屬性,則后面的屬性會(huì)覆蓋前面的屬性。

    b. 如果該函數(shù)只有一個(gè)參數(shù),當(dāng)參數(shù)為對(duì)象時(shí),直接返回該對(duì)象;當(dāng)參數(shù)不是對(duì)象時(shí),會(huì)先將參數(shù)轉(zhuǎn)為對(duì)象后返回。

    c. assign 的屬性拷貝是淺拷貝

  • Object.is(value1, value2)

    用于比較兩個(gè)值是否嚴(yán)格相等,與 (===) 基本類似。

    Object.is('q','q')   // true
    Object.is([1],[1])   // false 對(duì)象類型要同時(shí)比較地址和值
    Object.is({q: 1},{q: 1})  //false 對(duì)象類型要同時(shí)比較地址和值
    

    與 (===) 的區(qū)別

    // 1. +0 不等于 -0
    Object.is(+0, -1)   // false
    +0  === -0          // true
    // 2. NaN 等于本身
    Object.is(NaN, NaN)  // true
    NaN === NaN          // false
    

2.6 數(shù)組

數(shù)組的創(chuàng)建
  • Array.of()

    將參數(shù)中所有值作為元素形成數(shù)組。

    console.log(Array.of(1,2,3,4))   // [1,2,3,4]
    //參數(shù)值可為不同類型
    console.log(Array.of(1,'2',true))  // [1, '2', true]
    //參數(shù)為空時(shí)返回空數(shù)組
    console.log(Array.of())  // []
    
  • Array.from()

    將類數(shù)組對(duì)象或可迭代對(duì)象轉(zhuǎn)化為數(shù)組

    // 參數(shù)為數(shù)組,返回與原數(shù)組一樣的數(shù)組
    console.log(Arrays.from([1,2]))   // [1, 2]
    //參數(shù)含空位
    console.log(Arrays.from([1, ,3])) // [1, undefined, 3]
    
  • 類數(shù)組

    一個(gè)類數(shù)組對(duì)象必須含有 length 屬性,且元素屬性名必須是數(shù)組或可轉(zhuǎn)換為數(shù)值的字符。

    let arr = Array.from({
        0: '1',
        1: '2',
        2: '3',
        length: 3
    })
    console.log(arr)    //['1','2','3']
    
  • 轉(zhuǎn)換可迭代對(duì)象

    // 轉(zhuǎn)換 map
    // 轉(zhuǎn)換 set
    // 轉(zhuǎn)換 string
    let arr = Array.from(map | set | string)
    
擴(kuò)展的方法
方法名 描述 示例
find() 查找數(shù)組中符合條件的元素,若有多個(gè),返回第一個(gè)元素 Array.from(1,2,3).find(x=>x>2) // 3
findIndex() 查找數(shù)組中符合條件的元素的索引,若有多個(gè),返回第一個(gè) Array.from(1,2,3).findIndex(x=>x>2) // 2
fill() 將一定范圍索引的數(shù)組元素填充為單個(gè)指定的值 Array.from(1,2,3,4).fill(0,1,2) // [1,0,3,4]
copyWithin() 將一定范圍索引的數(shù)組元素修改為此數(shù)組另一指定范圍索引的元素 Array.from(1,2,3,4).copyWithin(0,2,4) // [3,4,3,4]
entries() 遍歷鍵值對(duì) N/A
keys() 遍歷鍵名 N/A
values() 遍歷鍵值 N/A
includes() 數(shù)組是否包含指定值 N/A
flat() 嵌套數(shù)組轉(zhuǎn)一維數(shù)組 [1,[2,3]].flat() // [1,2,3]
flatMap() 先對(duì)數(shù)組中每個(gè)元素進(jìn)行了處理,再對(duì)數(shù)組執(zhí)行flat() [1,[2,3]].flatMap(x=>x*2) // [2,4,6]
數(shù)組緩沖區(qū)

數(shù)組緩沖區(qū)是內(nèi)存中的一段地址。實(shí)際字節(jié)數(shù)在創(chuàng)建時(shí)確定,之后只可修改其中的數(shù)據(jù),不可修改大小。

let buffer = ArrayBuffer(10)
console.log(buffer.byteLength)   // 10
  • 視圖

    視圖是用來操作內(nèi)存的接口。視圖可以操作數(shù)組緩沖區(qū)或緩沖區(qū)字節(jié)的子集,并按照其中一種數(shù)值數(shù)據(jù)類型來讀取和寫入數(shù)據(jù)。

    DataView 類型是一種通用的數(shù)組緩沖區(qū)視圖,其支持所有8種數(shù)值型數(shù)據(jù)類型。

    //默認(rèn)DataView可操作緩沖區(qū)的全部內(nèi)容
    let buffer = new ArrayBuffer(10)
    let dataView = new DataView(buffer)
    dataView.setInt8(0,1)
    console.log(dataView.getInt8(0))   //1
    //通過設(shè)置偏移量和長度指定DataView可操作的字節(jié)范圍
    let dataView1 = new DataView(buffer, 0, 3)
    dataView1.setInt8(5,1)  // RangeError
    
定型數(shù)組

數(shù)組緩沖區(qū)特定類型的視圖??梢詮?qiáng)制使用特定的數(shù)據(jù)類型,而不是使用通用的DataView對(duì)象來操作數(shù)組緩沖區(qū)。

let buffer = new ArrayBuffer(10)
let view = new Int8Array(buffer)
console.log(view.byteLength)   // 10

length 屬性不可寫,如果嘗試修改這個(gè)值,在非嚴(yán)格模式下會(huì)直接忽略該操作,在嚴(yán)格模式下會(huì)拋出錯(cuò)誤。

擴(kuò)展運(yùn)算符
  • 復(fù)制數(shù)組
let arr = [1,2],
    arr1 = [...arr]
console.log(arr1)   //[1,2]
//合并數(shù)組
console.log(...[1,2],...[3,4])     // [1,2,3,4]

3 運(yùn)算符與語句

3.1 函數(shù)

  • 函數(shù)參數(shù)的擴(kuò)展

    默認(rèn)參數(shù)

    function fn(name, age = 17){ console.log(name + ', ' + age)}
    fn('Amy', 18)  // Amy, 18
    fn('Amy')      // Amy, 17
    

    a. 使用函數(shù)的默認(rèn)參數(shù)時(shí),不允許有同名參數(shù)。

    b. 只有在未傳遞參數(shù),或者參數(shù)為undefined時(shí),才會(huì)使用默認(rèn)參數(shù),null值被認(rèn)為是有效的值傳遞。

    c. 函數(shù)參數(shù)默認(rèn)值存在暫時(shí)性死區(qū),在函數(shù)參數(shù)默認(rèn)值表達(dá)式中,還未初始化賦值的參數(shù)值無法作為其它參數(shù)的默認(rèn)值。

    不定參數(shù)

    不定參數(shù)用來表示不確定的參數(shù)個(gè)數(shù),形如, ...變量名,由...加上一個(gè)具名參數(shù)標(biāo)識(shí)符組成。具名參數(shù)只能放在參數(shù)組的最后,并且有且只有一個(gè)不定參數(shù)。

    function fn(...values){ console.log(values.length)}
    fn(1, 2)      // 2
    fn(1,2,3,4)   // 4
    
  • 箭頭函數(shù)

    箭頭函數(shù)提供了一種更加簡潔的函數(shù)書寫方式。

    let f = v => v
    // 等價(jià)于
    let f = function(v){ console.log(v)}
    f(1)   // 1
    

    當(dāng)箭頭函數(shù)沒有參數(shù)或者有多個(gè)參數(shù)時(shí),要用()括起來。

    當(dāng)箭頭函數(shù)有多行語句,用{} 包裹起來,表示代碼塊,當(dāng)只有一行語句,并且需要返回結(jié)果時(shí),可以省略{} 結(jié)果自動(dòng)返回。

    let f = (a,b) => {
        let result = a + b
        return result
    }
    f(6,2)   // 8
    

    當(dāng)箭頭函數(shù)要返回對(duì)象的時(shí)候,為了區(qū)分于代碼塊,要用 () 將對(duì)象包裹起來

    let f = (id,name) = ({ id: id, name: name})
    f(6,2)  // {id: 6, name: 2}
    

    沒有 this, super, arguments和new.target 綁定。

    箭頭函數(shù)體中的 this 對(duì)象,是定義函數(shù)時(shí)的對(duì)象,而不是使用函數(shù)時(shí)對(duì)象。

  • 適用場景

    N/A

  • 不適用場景

    N/A

3.2 class 類

class(類)作為對(duì)象的模板被引入,可以通過class關(guān)鍵字定義類。其實(shí)class的本質(zhì)就是function,它可以看作一個(gè)語法糖,讓對(duì)象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法。

// 匿名類
let Example = class {
    constructor(a){
        this.a = a
    }
}
// 命名類
let Example = class Example{
    constructor(a){
        this.a = a
    }
}

a. 類定義不會(huì)被提升,這意味著,必須在訪問前對(duì)類進(jìn)行定義,否則就會(huì)報(bào)錯(cuò)。

b. 類中方法不需要 function 關(guān)鍵字

c. 方法間不能加分號(hào)。

  • 類的主體 (以下屬性、方法、實(shí)例化,與其它任一編程語言都是相通的,不再作解釋)

    屬性

    靜態(tài)屬性

    公共屬性

    實(shí)例屬性

    name屬性

    方法

    constructor方法

    靜態(tài)方法

    原型方法
    
    實(shí)例方法
    

    類的實(shí)例化

    new

    實(shí)例化對(duì)象
    
  • decorator

    decorator 是一個(gè)函數(shù),用來修飾類的行為,在代碼編譯時(shí)產(chǎn)生作用。

    類修飾

    function testable(target){
        target.isTestable = true
    }
    
    @testable
    class Example{}
    Example.isTestable    // true
    

    上面的例子添加的是靜態(tài)屬性,若要添加實(shí)例屬性,在類的 prototype 上操作即可。

    方法修飾

    class Example{
        @writable
        sum(a, b) {return a + b}
    }
    function writable(target, name, descriptor){
        descriptor.writable = false
        return descriptor
    }
    

    修飾器執(zhí)行順序: 由外向內(nèi)進(jìn)入,由內(nèi)向外執(zhí)行。

  • 封裝與繼承

    getter / setter

    class Example{
        constructor(a, b) {
            this.a = a; // 實(shí)例化時(shí)調(diào)用 set 方法
            this.b = b;
        }
        get a(){
            console.log('getter');
            return this.a;
        }
        set a(a){
            console.log('setter');
            this.a = a; // 自身遞歸調(diào)用
        }
    }
    let exam = new Example(1,2); // 不斷輸出 setter ,最終導(dǎo)致 RangeError
    

    extends

    class Child extends Father{ ... }
    

    Super

    子類constructor方法中必須有super,且必須出現(xiàn)在this之前

    class Father {
        constructor() {}
    }
    class Child extends Father {
        constructor() {}
        // or 
        // constructor(a) {
            // this.a = a;
            // super();
        // }
    }
    let test = new Child();
    

    不可繼承常規(guī)對(duì)象

    var Father = {
        // ...
    }
    class Child extends Father{
        // ...
    }
    // Uncaught TypeError: Class extends value #<Object> is not a constructor or null
    

3.3 ES6 模塊

ES6引入了模塊化,其設(shè)計(jì)思想是在編譯時(shí)就能確定模塊的依賴關(guān)系,以及輸入和輸出的變量。

ES6的模塊分為導(dǎo)出(export) @與導(dǎo)入(import) 兩個(gè)模塊

  • 特點(diǎn)

    a. ES6 的模塊自動(dòng)開啟嚴(yán)格模式,不管你有沒有在模塊頭部加上 use strict。

    b. 模塊中可以導(dǎo)入和導(dǎo)出各種類型的變量,如函數(shù),對(duì)象,字符串,數(shù)字,布爾值,類等。

    c. 每個(gè)模塊都有自己的上下文,每一個(gè)模塊內(nèi)聲明的變量都是局部變量,不會(huì)污染全局作用域。

    d. 每一個(gè)模塊只加載一次(單例),若再去加載同目錄下的同文件,直接從內(nèi)存中讀取。

  • export 與 import

    模塊導(dǎo)入導(dǎo)出各種類型的變量,如字符串,數(shù)值,函數(shù),類。

    a. 導(dǎo)出的函數(shù)聲明與類聲明必須要有名稱(export default 命令另外考慮)。

    b. 不僅能導(dǎo)出聲明還能導(dǎo)出引用(函數(shù))。

    c. export 命令可以出現(xiàn)在模塊的任何位置,但必須處于模塊頂層。

    d.import 命令會(huì)提升到整個(gè)模塊的頭部,首先執(zhí)行。

import 命令的特點(diǎn):

  • 只讀屬性

  • 單例模式

export default 命令:

a. 在一個(gè)文件或模塊中,export、import 可以有多個(gè),export default 僅有一個(gè)。

b. export default 中的 default 是對(duì)應(yīng)的導(dǎo)出接口變量。

c. 通過 export 方式導(dǎo)出,在導(dǎo)入時(shí)要加{ },export default 則不需要。

d. export default 向外暴露的成員,可以使用任意變量來接收。
  • 復(fù)合使用

    export 與 import 可以在同一模塊中使用,使用特點(diǎn):

    a. 可以將導(dǎo)出接口改名,包括default。

    b. 復(fù)合使用 export 與 import ,也可以導(dǎo)出全部,當(dāng)前模塊導(dǎo)出的接口會(huì)覆蓋繼承導(dǎo)出的。

4 異步編程

4.1 Promise 對(duì)象

Promise是異步編程的一種解決方案。從語法上講,Promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息。

Promise 狀態(tài)

Promise 異步操作有三種狀態(tài):pending(進(jìn)行中), fulfilled(已成功), rejected(已失敗)。除了異步操作的結(jié)果,任何其他操作都無法改變這個(gè)狀態(tài)。

const p1 = new Promise(function(resolve,reject){
    resolve('success1');
    resolve('success2');
}); 
const p2 = new Promise(function(resolve,reject){  
    resolve('success3'); 
    reject('reject');
});
p1.then(function(value){  
    console.log(value); // success1
});
p2.then(function(value){ 
    console.log(value); // success3
});

狀態(tài)的缺點(diǎn)

a. 無法取消 Promise ,一旦新建它就會(huì)立即執(zhí)行,無法中途取消。

b. 如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。

c. 當(dāng)處于 pending 狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。

then 方法

then 方法接收兩個(gè)函數(shù)作為參數(shù),第一個(gè)參數(shù)是 Promise 執(zhí)行成功時(shí)的回調(diào),第二個(gè)參數(shù)是 Promise 執(zhí)行失敗時(shí)的回調(diào),兩個(gè)函數(shù)只會(huì)有一個(gè)被調(diào)用。

const p = new Promise(function(resolve,reject){
  resolve('success');
});
p.then(function(value){
  console.log(value);
});
console.log('first');
// first
// success

簡便的Promise鏈?zhǔn)骄幊套詈帽3直馄交灰短譖romise。

注意總是返回或終止Promise鏈。

4.2 Generator 函數(shù)

ES6新引入的 Generator函數(shù),可以通過yield關(guān)鍵字,把函數(shù)的執(zhí)行流掛起,為改變執(zhí)行流程提供了可能,從而為異步編程提供解決方案。

  • Generator 函數(shù)組成

    Generator 有兩個(gè)區(qū)分于普通函數(shù)的部分:

    a. 一是在function 后面,函數(shù)名之前有個(gè) *

    b. 函數(shù)內(nèi)部有 yield 表達(dá)式。

    function* func(){
      console.log("one");
         yield '1';
         console.log("two");
         yield '2'; 
         console.log("three");
         return '3';
    }
    
  • 執(zhí)行機(jī)制

    調(diào)用 Generator 函數(shù)和調(diào)用普通函數(shù)一樣,在函數(shù)名后面加上()即可,但是 Generator 函數(shù)不會(huì)像普通函數(shù)一樣立即執(zhí)行,而是返回一個(gè)指向內(nèi)部狀態(tài)對(duì)象的指針,所以要調(diào)用遍歷器對(duì)象Iterator 的 next 方法,指針就會(huì)從函數(shù)頭部或者上一次停下來的地方開始執(zhí)行。

    let f = func()
    f.next()
    // one
    // {value: "1", done: false}
     
    f.next()
    // two
    // {value: "2", done: false}
     
    f.next()
    // three
    // {value: "3", done: true}
     
    f.next()
    // {value: undefined, done: true}
    

4.3 Async 函數(shù)

async 是 ES7 才有的與異步操作有關(guān)的關(guān)鍵字,和Promise, Generator 有很大關(guān)聯(lián)的。

async 函數(shù)返回一個(gè) Promise對(duì)象,可以使用 then 方法添加回調(diào)函數(shù)。

async function helloAsync(){
    return 'hello async'
}
console.log(helloAsync())   // Promise {<resolved>: 'helloAsync'}
helloAsync().then(v=>{
    console.log(v)            // hello async
})

async 函數(shù)中可能會(huì)有 await 表達(dá)式,async 函數(shù)執(zhí)行時(shí),如果遇到 await 就會(huì)暫停執(zhí)行,等到觸發(fā)的異步操作完成后,恢復(fù)async 函數(shù)的執(zhí)行并返回解析值。

await 關(guān)鍵字僅在 async function 中有效。

function testAwait(){
   return new Promise((resolve) => {
       setTimeout(function(){
          console.log("testAwait");
          resolve();
       }, 1000);
   });
}
async function helloAsync(){
   await testAwait();
   console.log("helloAsync");
 }
helloAsync(); 
// testAwait
// helloAsync

await 針對(duì)所跟不同表達(dá)式的處理方式:

  • Promise 對(duì)象: await 會(huì)暫停執(zhí)行,等待 Promise 對(duì)象 resolve, 然后恢復(fù)async函數(shù)的執(zhí)行并返回解析值。
  • 非Promise對(duì)象: 直接返回對(duì)應(yīng)的值。

總結(jié)

N/A

參考

ES 6 教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容