數(shù)值的擴(kuò)展 date:(2019.07.17)
二進(jìn)制和八進(jìn)制表示法
Number.isFinite(), Number.isNaN()
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true' / 0) // true
Number.isNaN('true' / 'true') // true
- 它們與傳統(tǒng)的全局方法isFinite()和isNaN()的區(qū)別在于透罢,傳統(tǒng)方法先調(diào)用Number()將非數(shù)值的值轉(zhuǎn)為數(shù)值,再進(jìn)行判斷丧慈,而這兩個(gè)新方法只對(duì)數(shù)值有效仙蚜,Number.isFinite()對(duì)于非數(shù)值一律返回false, Number.isNaN()只有對(duì)于NaN才返回true怜械,非NaN一律返回false灾而。
Number.parseInt(), Number.parseFloat()
- ES6 將全局方法parseInt()和parseFloat(),移植到Number對(duì)象上面,行為完全保持不變叫挟,這樣做的目的艰匙,是逐步減少全局性方法,使得語(yǔ)言逐步模塊化
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
Number.isInteger()
- 用來(lái)判斷一個(gè)數(shù)值是否為整數(shù)
- JavaScript 內(nèi)部抹恳,整數(shù)和浮點(diǎn)數(shù)采用的是同樣的儲(chǔ)存方法员凝,所以 25 和 25.0 被視為同一個(gè)值
- 如果參數(shù)不是數(shù)值,Number.isInteger返回false
Number.EPSILON
- 它表示 1 與大于 1 的最小浮點(diǎn)數(shù)之間的差
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true
上面的代碼為浮點(diǎn)數(shù)運(yùn)算奋献,部署了一個(gè)誤差檢查函數(shù)
Math 對(duì)象的擴(kuò)展
ES6 在 Math 對(duì)象上新增了 17 個(gè)與數(shù)學(xué)相關(guān)的方法健霹。所有這些方法都是靜態(tài)方法,只能在 Math 對(duì)象上調(diào)用
- Math.trunc方法用于去除一個(gè)數(shù)的小數(shù)部分瓶蚂,返回整數(shù)部分,對(duì)于非數(shù)值糖埋,Math.trunc內(nèi)部使用Number方法將其先轉(zhuǎn)為數(shù)值,對(duì)于空值和無(wú)法截取整數(shù)的值,返回NaN
Math.trunc = Math.trunc || function(x) {
return x < 0 ? Math.ceil(x) : Math.floor(x);
};
- Math.sign方法用來(lái)判斷一個(gè)數(shù)到底是正數(shù)窃这、負(fù)數(shù)瞳别、還是零。對(duì)于非數(shù)值杭攻,會(huì)先將其轉(zhuǎn)換為數(shù)值
它會(huì)返回五種值祟敛。
參數(shù)為正數(shù),返回+1朴上;
參數(shù)為負(fù)數(shù)垒棋,返回-1;
參數(shù)為 0痪宰,返回0叼架;
參數(shù)為-0,返回-0;
其他值衣撬,返回NaN
Math.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(undefined)
- Math.cbrt方法用于計(jì)算一個(gè)數(shù)的立方根
- Math.hypot方法返回所有參數(shù)的平方和的平方根
指數(shù)運(yùn)算符
- ES2016 新增了一個(gè)指數(shù)運(yùn)算符(**)
2 ** 2 // 4
2 ** 3 // 8
- 指數(shù)運(yùn)算符可以與等號(hào)結(jié)合乖订,形成一個(gè)新的賦值運(yùn)算符(**=)
數(shù)組的擴(kuò)展
1.擴(kuò)展運(yùn)算符
含義
- 擴(kuò)展運(yùn)算符(spread)是三個(gè)點(diǎn)(...)。它好比 rest 參數(shù)的逆運(yùn)算具练,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列乍构。
console.log(...[1, 2, 3])
// 1 2 3
- 該運(yùn)算符主要用于函數(shù)調(diào)用
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42
- 擴(kuò)展運(yùn)算符后面還可以放置表達(dá)式
- 如果擴(kuò)展運(yùn)算符后面是一個(gè)空數(shù)組,則不產(chǎn)生任何效果
- 只有函數(shù)調(diào)用時(shí)扛点,擴(kuò)展運(yùn)算符才可以放在圓括號(hào)中哥遮,否則會(huì)報(bào)錯(cuò)
- 替代函數(shù)的 apply 方法
擴(kuò)展運(yùn)算符的應(yīng)用
- 復(fù)制數(shù)組,只是復(fù)制了指向底層數(shù)據(jù)結(jié)構(gòu)的指針
- 合并數(shù)組陵究,但是淺拷貝
- 與解構(gòu)賦值結(jié)合
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
- 如果將擴(kuò)展運(yùn)算符用于數(shù)組賦值眠饮,只能放在參數(shù)的最后一位,否則會(huì)報(bào)錯(cuò)
- 擴(kuò)展運(yùn)算符還可以將字符串轉(zhuǎn)為真正的數(shù)組
- 實(shí)現(xiàn)了 Iterator 接口的對(duì)象铜邮,都可以用擴(kuò)展運(yùn)算符轉(zhuǎn)為真正的數(shù)組
- Map 和 Set 結(jié)構(gòu)仪召,Generator 函數(shù)寨蹋,都可以使用擴(kuò)展運(yùn)算符
2.Array.from()
- Array.from方法用于將兩類對(duì)象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對(duì)象(array-like object)和可遍歷(iterable)的對(duì)象(包括 ES6 新增的數(shù)據(jù)結(jié)構(gòu) Set 和 Map)
- 只要是部署了 Iterator 接口的數(shù)據(jù)結(jié)構(gòu),Array.from都能將其轉(zhuǎn)為數(shù)組
- 如果參數(shù)是一個(gè)真正的數(shù)組扔茅,Array.from會(huì)返回一個(gè)一模一樣的新數(shù)組
- Array.from還可以接受第二個(gè)參數(shù)已旧,作用類似于數(shù)組的map方法,用來(lái)對(duì)每個(gè)元素進(jìn)行處理召娜,將處理后的值放入返回的數(shù)組
3.Array.of()
- Array.of方法用于將一組值运褪,轉(zhuǎn)換為數(shù)組
- 這個(gè)方法的主要目的,是彌補(bǔ)數(shù)組構(gòu)造函數(shù)Array()的不足玖瘸。因?yàn)閰?shù)個(gè)數(shù)的不同吐句,會(huì)導(dǎo)致Array()的行為有差異。
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
- Array.of基本上可以用來(lái)替代Array()或new Array()店读,并且不存在由于參數(shù)不同而導(dǎo)致的重載
4.數(shù)組實(shí)例的copyWithin()
- 在當(dāng)前數(shù)組內(nèi)部,將指定位置的成員復(fù)制到其他位置(會(huì)覆蓋原有成員)攀芯,然后返回當(dāng)前數(shù)組屯断,會(huì)修改當(dāng)前數(shù)組
Array.prototype.copyWithin(target, start = 0, end = this.length)
- 它接受三個(gè)參數(shù):
- target(必需):從該位置開始替換數(shù)據(jù)。如果為負(fù)值侣诺,表示倒數(shù)殖演。
- start(可選):從該位置開始讀取數(shù)據(jù),默認(rèn)為 0年鸳。如果為負(fù)值趴久,表示從末尾開始計(jì)算。
- end(可選):到該位置前停止讀取數(shù)據(jù)搔确,默認(rèn)等于數(shù)組長(zhǎng)度彼棍。如果為負(fù)值,表示從末尾開始計(jì)算膳算。
- 這三個(gè)參數(shù)都應(yīng)該是數(shù)值座硕,如果不是,會(huì)自動(dòng)轉(zhuǎn)為數(shù)值涕蜂。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
5.數(shù)組實(shí)例的find()和findIndex()
- 數(shù)組實(shí)例的find方法华匾,用于找出第一個(gè)符合條件的數(shù)組成員。它的參數(shù)是一個(gè)回調(diào)函數(shù)机隙,所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù)蜘拉,直到找出第一個(gè)返回值為true的成員,然后返回該成員有鹿。如果沒有符合條件的成員旭旭,則返回undefined。
[1, 4, -5, 10].find((n) => n < 0)
// -5
- find方法的回調(diào)函數(shù)可以接受三個(gè)參數(shù)印颤,依次為當(dāng)前的值您机、當(dāng)前的位置和原數(shù)組
- 數(shù)組實(shí)例的findIndex方法的用法與find方法非常類似,返回第一個(gè)符合條件的數(shù)組成員的位置,如果所有成員都不符合條件际看,則返回-1
- find函數(shù)接收了第二個(gè)參數(shù)person對(duì)象咸产,回調(diào)函數(shù)中的this對(duì)象指向person對(duì)象
- 這兩個(gè)方法都可以發(fā)現(xiàn)NaN,彌補(bǔ)了數(shù)組的indexOf方法的不足
6.數(shù)組實(shí)例的fill()
- fill方法使用給定值仲闽,填充一個(gè)數(shù)組
- fill方法用于空數(shù)組的初始化非常方便脑溢。數(shù)組中已有的元素,會(huì)被全部抹去赖欣。
- fill方法還可以接受第二個(gè)和第三個(gè)參數(shù)屑彻,用于指定填充的起始位置和結(jié)束位置
7.數(shù)組實(shí)例的entries(),keys()和values()
- 用于遍歷數(shù)組
- 可以用for...of循環(huán)進(jìn)行遍歷,唯一的區(qū)別是keys()是對(duì)鍵名的遍歷顶吮、values()是對(duì)鍵值的遍歷社牲,entries()是對(duì)鍵值對(duì)的遍歷
8.數(shù)組實(shí)例的includes()
- 方法返回一個(gè)布爾值,表示某個(gè)數(shù)組是否包含給定的值悴了,該方法的第二個(gè)參數(shù)表示搜索的起始位置
9.數(shù)組實(shí)例的flat(),flatMap()
- 數(shù)組的成員有時(shí)還是數(shù)組搏恤,Array.prototype.flat()用于將嵌套的數(shù)組“拉平”,變成一維的數(shù)組湃交,該方法返回一個(gè)新數(shù)組熟空,對(duì)原數(shù)據(jù)沒有影響
- 默認(rèn)只會(huì)“拉平”一層,如果想要“拉平”多層的嵌套數(shù)組搞莺,可以將flat()方法的參數(shù)寫成一個(gè)整數(shù)息罗,表示想要拉平的層數(shù),默認(rèn)為1
[1, 2, [3, [4, 5]]].flat() // [1, 2, 3, [4, 5]] [1, 2, [3, [4, 5]]].flat(2) // [1, 2, 3, 4, 5]
- 如果不管有多少層嵌套才沧,都要轉(zhuǎn)成一維數(shù)組迈喉,可以用Infinity關(guān)鍵字作為參數(shù)
- 如果原數(shù)組有空位,flat()方法會(huì)跳過空位温圆。
[1, 2, , 4, 5].flat() // [1, 2, 4, 5]
- 遍歷函數(shù)返回的是一個(gè)雙層的數(shù)組弊添,但是默認(rèn)只能展開一層,因此flatMap()返回的還是一個(gè)嵌套數(shù)組
10.數(shù)組的空位
- 空位不是undefined捌木,一個(gè)位置的值等于undefined油坝,依然是有值的,空位是沒有任何值,in運(yùn)算符可以說(shuō)明這一點(diǎn)
- Array.from方法會(huì)將數(shù)組的空位刨裆,轉(zhuǎn)為undefined
- 擴(kuò)展運(yùn)算符(...)也會(huì)將空位轉(zhuǎn)為undefined
- copyWithin()會(huì)連空位一起拷貝
- fill()會(huì)將空位視為正常的數(shù)組位置
- for...of循環(huán)也會(huì)遍歷空位
- entries()澈圈、keys()、values()帆啃、find()和findIndex()會(huì)將空位處理成undefined
TDD作業(yè)
Number API
<p align="center" style="display:inline-block">
<p>Number->Number.isInteger()</p>
<img src="./img/TDD-Number.isInteger.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Number->Number.isNaN()</p>
<img src="./img/TDD-Number.isNaN.png" height="150">
</p>
Array API
<p align="center" style="display:inline-block">
<p> Array->Array.from()</p>
<img src="./img/TDD-Array.from.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.from()</p>
<img src="./img/TDD-Array.from.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.of()</p>
<img src="./img/TDD-Array.of.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.fill()</p>
<img src="./img/TDD-Array.fill.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.find()</p>
<img src="./img/TDD-Array.find.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.findIndex()</p>
<img src="./img/TDD-Array.findIndex.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.entries()</p>
<img src="./img/TDD-Array.entries.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.keys()</p>
<img src="./img/TDD-Array.keys.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Array->Array.values()</p>
<img src="./img/TDD-Array.values.png" height="150">
</p>
圖區(qū):
date:(2019.07.18)
let const
- for循環(huán)的計(jì)數(shù)器很適合let命令
- let聲明不存在變量提升
- let const聲明變量瞬女,暫存性死區(qū)(TDZ)
- 暫時(shí)性死區(qū)的本質(zhì)就是,只要一進(jìn)入當(dāng)前作用域努潘,所要使用的變量就已經(jīng)存在了诽偷,但是不可獲取坤学,只有等到聲明變量的那一行代碼出現(xiàn),才可以獲取和使用該變量报慕。
- 不允許出現(xiàn)重復(fù)聲明
塊級(jí)作用域
- 為什么需要塊級(jí)作用域深浮?
- 內(nèi)層變量可能會(huì)覆蓋外層變量
- 用來(lái)計(jì)數(shù)的循環(huán)變量泄露為全局變量
- es6的塊級(jí)作用域
- ES6 允許塊級(jí)作用域的任意嵌套
- 使得立即執(zhí)行函數(shù)不那么必要了
- 塊級(jí)作用域與函數(shù)聲明
- ES5 規(guī)定,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明眠冈,不能在塊級(jí)作用域聲明飞苇,瀏覽器沒有遵守這個(gè)規(guī)定
- ES6 的塊級(jí)作用域必須有大括號(hào)
const命令
- 基本用法
- const聲明一個(gè)只讀的常量。一旦聲明蜗顽,常量的值就不能改變
- const一旦聲明變量布卡,就必須立即初始化
- 只在聲明所在的塊級(jí)作用域內(nèi)有效
- 聲明的常量也是不提升,同樣存在暫時(shí)性死區(qū)雇盖,只能在聲明的位置后面使用
- 不可重復(fù)聲明
- 本質(zhì)
- const實(shí)際上保證的忿等,并不是變量的值不得改動(dòng),而是變量指向的那個(gè)內(nèi)存地址所保存的數(shù)據(jù)不得改動(dòng)
- 可以用const什么{}和[]且賦值不會(huì)報(bào)錯(cuò)
- 想將對(duì)象凍結(jié)崔挖,應(yīng)該使用Object.freeze方法
- ES6 聲明變量的六種方法
- var这弧、function、let虚汛、const、import皇帮、class卷哩,ES6 一共有 6 種聲明變量的方法。
頂層對(duì)象的屬性
- 頂層對(duì)象属拾,在瀏覽器環(huán)境指的是window對(duì)象将谊,在 Node 指的是global對(duì)象。ES5 之中渐白,頂層對(duì)象的屬性與全局變量是等價(jià)的
- var命令和function命令聲明的全局變量尊浓,依舊是頂層對(duì)象的屬性
- let命令、const命令纯衍、class命令聲明的全局變量栋齿,不屬于頂層對(duì)象的屬性。也就是說(shuō)襟诸,從 ES6 開始瓦堵,全局變量將逐步與頂層對(duì)象的屬性脫鉤
globalThis對(duì)象
- JavaScript 語(yǔ)言存在一個(gè)頂層對(duì)象,它提供全局環(huán)境歌亲,但是菇用,頂層對(duì)象在各種實(shí)現(xiàn)里面是不統(tǒng)一的
- 瀏覽器里面,頂層對(duì)象是window陷揪,但 Node 和 Web Worker 沒有window
- 瀏覽器和 Web Worker 里面惋鸥,self也指向頂層對(duì)象杂穷,但是 Node 沒有self
- Node 里面,頂層對(duì)象是global卦绣,但其他環(huán)境都不支持
字符串的擴(kuò)展
1.字符Unicode表示法
- ES6 加強(qiáng)了對(duì) Unicode 的支持耐量,允許采用\uxxxx形式表示一個(gè)字符,其中xxxx表示字符的 Unicode 碼點(diǎn)迎卤。
"\u0061"
// "a"
- JavaScript 共有 6 種方法可以表示一個(gè)字符拴鸵。
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
2.字符串的遍歷器接口
- ES6 為字符串添加了遍歷器接口,使得字符串可以被for...of循環(huán)遍歷
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
3.直接輸入U(xiǎn)+2028和U+2029
-
javaScript 字符串允許直接輸入字符蜗搔,以及輸入字符的轉(zhuǎn)義形式
'中' === '\u4e2d' // true
javaScript 規(guī)定有5個(gè)字符劲藐,不能在字符串里面直接使用,只能使用轉(zhuǎn)義形式樟凄。
U+005C:反斜杠(reverse solidus)
U+000D:回車(carriage return)
U+2028:行分隔符(line separator)
U+2029:段分隔符(paragraph separator)
U+000A:換行符(line feed)
4.JSON.stringify()的改造
5.模板字符串
- 模板字符串(template string)是增強(qiáng)版的字符串聘芜,用反引號(hào)(`)標(biāo)識(shí),它可以當(dāng)作普通字符串使用缝龄,也可以用來(lái)定義多行字符串汰现,或者在字符串中嵌入變量
// 普通字符串
`In JavaScript '\n' is a line-feed.`
// 多行字符串
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// 字符串中嵌入變量
let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
- 模板字符串表示多行字符串,所有的空格和縮進(jìn)都會(huì)被保留在輸出之中叔壤,使用trim方法消除它
- 模板字符串中嵌入變量瞎饲,需要將變量名寫在${}之中,大括號(hào)內(nèi)部可以放入任意的 JavaScript 表達(dá)式炼绘,可以進(jìn)行運(yùn)算嗅战,以及引用對(duì)象屬性
let x = 1;
let y = 2;
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"
let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"
- 模板字符串之中還能調(diào)用函數(shù)
function fn() {
return "Hello World";
}
`foo ${fn()} bar`
- 模板字符串甚至還能嵌套
6.實(shí)例:模板編譯
- 使用<%...%>放置 JavaScript 代碼,使用<%= ... %>輸出 JavaScript 表達(dá)式
7.標(biāo)簽?zāi)0?/h3>
- 模板字符串的功能俺亮,不僅僅是上面這些驮捍。它可以緊跟在一個(gè)函數(shù)名后面,該函數(shù)將被調(diào)用來(lái)處理這個(gè)模板字符串脚曾。這被稱為“標(biāo)簽?zāi)0濉惫δ?/li>
- 標(biāo)簽?zāi)0迤鋵?shí)不是模板东且,而是函數(shù)調(diào)用的一種特殊形式”炯ィ“標(biāo)簽”指的就是函數(shù)珊泳,緊跟在后面的模板字符串就是它的參數(shù)
- 如果模板字符里面有變量,就不是簡(jiǎn)單的調(diào)用了拷沸,而是會(huì)將模板字符串先處理成多個(gè)參數(shù)旨椒,再調(diào)用函數(shù)
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
8.模板字符串的限制
函數(shù)的擴(kuò)展
1.函數(shù)參數(shù)的默認(rèn)值
基本用法
- ES6 允許為函數(shù)的參數(shù)設(shè)置默認(rèn)值,即直接寫在參數(shù)定義的后面
- 參數(shù)變量是默認(rèn)聲明的堵漱,所以不能用let或const再次聲明
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
- 使用參數(shù)默認(rèn)值時(shí)综慎,函數(shù)不能有同名參數(shù)
- 一個(gè)容易忽略的地方是,參數(shù)默認(rèn)值不是傳值的勤庐,而是每次都重新計(jì)算默認(rèn)值表達(dá)式的值示惊。也就是說(shuō)好港,參數(shù)默認(rèn)值是惰性求值的
與解構(gòu)賦值默認(rèn)值結(jié)合使用
- 參數(shù)默認(rèn)值可以與解構(gòu)賦值的默認(rèn)值,結(jié)合起來(lái)使用
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
- 上面代碼指定米罚,如果沒有提供參數(shù)钧汹,函數(shù)foo的參數(shù)默認(rèn)為一個(gè)空對(duì)象
參數(shù)默認(rèn)值的位置
- 通常情況下,定義了默認(rèn)值的參數(shù)录择,應(yīng)該是函數(shù)的尾參數(shù)拔莱。因?yàn)檫@樣比較容易看出來(lái),到底省略了哪些參數(shù)隘竭,如果非尾部的參數(shù)設(shè)置默認(rèn)值塘秦,實(shí)際上這個(gè)參數(shù)是沒法省略的
- 如果傳入undefined,將觸發(fā)該參數(shù)等于默認(rèn)值动看,null則沒有這個(gè)效果
函數(shù)的 length 屬性
-
指定了默認(rèn)值以后尊剔,函數(shù)的length屬性,將返回沒有指定默認(rèn)值的參數(shù)個(gè)數(shù)菱皆。也就是說(shuō)须误,指定了默認(rèn)值后,length屬性將失真
(function(...args) {}).length // 0
如果設(shè)置了默認(rèn)值的參數(shù)不是尾參數(shù)仇轻,那么length屬性也不再計(jì)入后面的參數(shù)了
(function(a, b=1, c){}).length
1
(function(a, b, c=1){}).length
2
(function(a, b, c){}).length
3
作用域
- 一旦設(shè)置了參數(shù)的默認(rèn)值京痢,函數(shù)進(jìn)行聲明初始化時(shí),參數(shù)會(huì)形成一個(gè)單獨(dú)的作用域
- 如果參數(shù)的默認(rèn)值是一個(gè)函數(shù)篷店,該函數(shù)的作用域也遵守這個(gè)規(guī)則
應(yīng)用
- 利用參數(shù)默認(rèn)值祭椰,可以指定某一個(gè)參數(shù)不得省略,如果省略就拋出一個(gè)錯(cuò)誤
function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
foo()
// Error: Missing parameter
- 參數(shù)的默認(rèn)值不是在定義時(shí)執(zhí)行船庇,而是在運(yùn)行時(shí)執(zhí)行
rest參數(shù)
- ES6 引入 rest 參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù)侣监,這樣就不需要使用arguments對(duì)象了鸭轮。rest 參數(shù)搭配的變量是一個(gè)數(shù)組,該變量將多余的參數(shù)放入數(shù)組中
- rest 參數(shù)之后不能再有其他參數(shù)
- 函數(shù)的length屬性橄霉,不包括 rest 參數(shù)
嚴(yán)格模式
- ES2016 規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值窃爷、解構(gòu)賦值、或者擴(kuò)展運(yùn)算符姓蜂,那么函數(shù)內(nèi)部就不能顯式設(shè)定為嚴(yán)格模式
- 兩種方法可以規(guī)避這種限制按厘。第一種是設(shè)定全局性的嚴(yán)格模式
- 第二種是把函數(shù)包在一個(gè)無(wú)參數(shù)的立即執(zhí)行函數(shù)里面
name 屬性
- 函數(shù)的name屬性,返回該函數(shù)的函數(shù)名
- 變量f等于一個(gè)匿名函數(shù)钱慢,ES5 和 ES6 的name屬性返回的值不一樣
- 如果將一個(gè)具名函數(shù)賦值給一個(gè)變量,則 ES5 和 ES6 的name屬性都返回這個(gè)具名函數(shù)原本的名字。
- Function構(gòu)造函數(shù)返回的函數(shù)實(shí)例嚣潜,name屬性的值為anonymous
- bind返回的函數(shù),name屬性值會(huì)加上bound前綴
箭頭函數(shù)
=>
如果箭頭函數(shù)不需要參數(shù)或需要多個(gè)參數(shù)草描,就使用一個(gè)圓括號(hào)代表參數(shù)部分
如果箭頭函數(shù)的代碼塊部分多于一條語(yǔ)句,就要使用大括號(hào)將它們括起來(lái)策严,并且使用return語(yǔ)句返回
如果箭頭函數(shù)直接返回一個(gè)對(duì)象穗慕,必須在對(duì)象外面加上括號(hào),否則會(huì)報(bào)錯(cuò)
-
如果箭頭函數(shù)只有一行語(yǔ)句妻导,且不需要返回值逛绵,可以采用下面的寫法,就不用寫大括號(hào)了
let fn = () => void doesNotReturn();
箭頭函數(shù)可以與變量解構(gòu)結(jié)合使用
箭頭函數(shù)的一個(gè)用處是簡(jiǎn)化回調(diào)函數(shù)
使用注意點(diǎn)
箭頭函數(shù)有幾個(gè)使用注意點(diǎn)倔韭。
- 函數(shù)體內(nèi)的this對(duì)象术浪,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象狐肢。
- 不可以當(dāng)作構(gòu)造函數(shù)添吗,也就是說(shuō),不可以使用new命令份名,否則會(huì)拋出一個(gè)錯(cuò)誤碟联。
- 不可以使用arguments對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在僵腺。如果要用鲤孵,可以用 rest 參數(shù)代替。
- 不可以使用yield命令辰如,因此箭頭函數(shù)不能用作 Generator 函數(shù)普监。
上面四點(diǎn)中,第一點(diǎn)尤其值得注意琉兜。this對(duì)象的指向是可變的凯正,但是在箭頭函數(shù)中,它是固定的
除了this豌蟋,以下三個(gè)變量在箭頭函數(shù)之中也是不存在的廊散,指向外層函數(shù)的對(duì)應(yīng)變量:arguments、super梧疲、new.target
由于箭頭函數(shù)沒有自己的this允睹,所以當(dāng)然也就不能用call()、apply()幌氮、bind()這些方法去改變this的指向
不適用場(chǎng)合
- 第一個(gè)場(chǎng)合是定義對(duì)象的方法缭受,且該方法內(nèi)部包括this
- 第二個(gè)場(chǎng)合是需要?jiǎng)討B(tài)this的時(shí)候,也不應(yīng)使用箭頭函數(shù)
嵌套的箭頭函數(shù)
尾調(diào)用優(yōu)化
- 尾調(diào)用(Tail Call)是函數(shù)式編程的一個(gè)重要概念该互,指某個(gè)函數(shù)的最后一步是調(diào)用另一個(gè)函數(shù)
- 以下三種情況米者,都不屬于尾調(diào)用
// 情況一
function f(x){
let y = g(x);
return y;
}
// 情況二
function f(x){
return g(x) + 1;
}
// 情況三
function f(x){
g(x);
}
- 尾調(diào)用不一定出現(xiàn)在函數(shù)尾部,只要是最后一步操作即可
尾遞歸
函數(shù)參數(shù)的尾逗號(hào)
- ES2017 允許函數(shù)的最后一個(gè)參數(shù)有尾逗號(hào)
Unicode
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
指定了默認(rèn)值以后尊剔,函數(shù)的length屬性,將返回沒有指定默認(rèn)值的參數(shù)個(gè)數(shù)菱皆。也就是說(shuō)须误,指定了默認(rèn)值后,length屬性將失真
(function(...args) {}).length // 0
如果設(shè)置了默認(rèn)值的參數(shù)不是尾參數(shù)仇轻,那么length屬性也不再計(jì)入后面的參數(shù)了
(function(a, b=1, c){}).length
1
(function(a, b, c=1){}).length
2
(function(a, b, c){}).length
3
function throwIfMissing() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = throwIfMissing()) {
return mustBeProvided;
}
foo()
// Error: Missing parameter
=>
如果箭頭函數(shù)不需要參數(shù)或需要多個(gè)參數(shù)草描,就使用一個(gè)圓括號(hào)代表參數(shù)部分
如果箭頭函數(shù)的代碼塊部分多于一條語(yǔ)句,就要使用大括號(hào)將它們括起來(lái)策严,并且使用return語(yǔ)句返回
如果箭頭函數(shù)直接返回一個(gè)對(duì)象穗慕,必須在對(duì)象外面加上括號(hào),否則會(huì)報(bào)錯(cuò)
如果箭頭函數(shù)只有一行語(yǔ)句妻导,且不需要返回值逛绵,可以采用下面的寫法,就不用寫大括號(hào)了
let fn = () => void doesNotReturn();
箭頭函數(shù)可以與變量解構(gòu)結(jié)合使用
箭頭函數(shù)的一個(gè)用處是簡(jiǎn)化回調(diào)函數(shù)
箭頭函數(shù)有幾個(gè)使用注意點(diǎn)倔韭。
- 函數(shù)體內(nèi)的this對(duì)象术浪,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象狐肢。
- 不可以當(dāng)作構(gòu)造函數(shù)添吗,也就是說(shuō),不可以使用new命令份名,否則會(huì)拋出一個(gè)錯(cuò)誤碟联。
- 不可以使用arguments對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在僵腺。如果要用鲤孵,可以用 rest 參數(shù)代替。
- 不可以使用yield命令辰如,因此箭頭函數(shù)不能用作 Generator 函數(shù)普监。
上面四點(diǎn)中,第一點(diǎn)尤其值得注意琉兜。this對(duì)象的指向是可變的凯正,但是在箭頭函數(shù)中,它是固定的
除了this豌蟋,以下三個(gè)變量在箭頭函數(shù)之中也是不存在的廊散,指向外層函數(shù)的對(duì)應(yīng)變量:arguments、super梧疲、new.target
由于箭頭函數(shù)沒有自己的this允睹,所以當(dāng)然也就不能用call()、apply()幌氮、bind()這些方法去改變this的指向
// 情況一
function f(x){
let y = g(x);
return y;
}
// 情況二
function f(x){
return g(x) + 1;
}
// 情況三
function f(x){
g(x);
}
<p align="center" style="display:inline-block">
<p> Unicode->In strings</p>
<img src="./img/TDD-unicode.png" height="150">
</p>
Template strings
<p align="center" style="display:inline-block">
<p> Template strings->basics</p>
<img src="./img/TDD-templateString-basics.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Template strings->Multiline</p>
<img src="./img/TDD-template-multiline.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Template strings->Tagged template strings</p>
<img src="./img/TDD-templateTagged.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Template strings->raw</p>
<img src="./img/TDD-template-String.raw.png" height="150">
</p>
Symbol
<p align="center" style="display:inline-block">
<p> Symbol->Symbol.for</p>
<img src="./img/TDD-symbol.for.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Symbol->Symbol.keyfor</p>
<img src="./img/TDD-symbol.keyfor.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Symbol->Basics</p>
<img src="./img/TDD-symbol-basics.png" height="150">
</p>
Object API
<p align="center" style="display:inline-block">
<p> Symbol->Object.is()</p>
<img src="./img/TDD-Object.is.png" height="150">
</p>
Modules
<p align="center" style="display:inline-block">
<p> Modules->import</p>
<img src="./img/TDD-module-import.png" height="150">
</p>
Default Parameters
<p align="center" style="display:inline-block">
<p> Default Parameters->Basics</p>
<img src="./img/TDD-DefaultParameters.png" height="150">
</p>
Spread operator
<p align="center" style="display:inline-block">
<p> Spread operator->With Array</p>
<img src="./img/TDD-spreaddestructuring.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Spread operator->With String</p>
<img src="./img/TDD-spread-string.png" height="150">
</p>
Rest operator
<p align="center" style="display:inline-block">
<p> Rest operator->As parameter
</p>
<img src="./img/TDD-rest-parameter.png" height="150">
</p>
<p align="center" style="display:inline-block">
<p> Rest operator->With destructuring</p>
<img src="./img/TDD-spread-string.png" height="150">
</p>
圖片區(qū)域:
date(07.22)
變量的解構(gòu)賦值
數(shù)組的解構(gòu)賦值
- 基本用法
- 按照一定模式宇智,從數(shù)組和對(duì)象中提取值塘雳,對(duì)變量進(jìn)行賦值陆盘,這被稱為解構(gòu)
- 本質(zhì)上,這種寫法屬于“模式匹配”败明,只要等號(hào)兩邊的模式相同隘马,左邊的變量就會(huì)被賦予對(duì)應(yīng)的值
- 解構(gòu)不成功,變量的值就等于undefined
- 不完全解構(gòu)妻顶,即等號(hào)左邊的模式酸员,只匹配一部分的等號(hào)右邊的數(shù)組。這種情況下讳嘱,解構(gòu)依然可以成功
- 如果等號(hào)的右邊不是數(shù)組(或者嚴(yán)格地說(shuō)幔嗦,不是可遍歷的結(jié)構(gòu)),那么將會(huì)報(bào)錯(cuò)
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
- 事實(shí)上沥潭,只要某種數(shù)據(jù)結(jié)構(gòu)具有 Iterator 接口邀泉,都可以采用數(shù)組形式的解構(gòu)賦值
- 默認(rèn)值
- ES6 內(nèi)部使用嚴(yán)格相等運(yùn)算符(===),判斷一個(gè)位置是否有值钝鸽。所以汇恤,只有當(dāng)一個(gè)數(shù)組成員嚴(yán)格等于undefined,默認(rèn)值才會(huì)生效
- 默認(rèn)值是一個(gè)表達(dá)式拔恰,那么這個(gè)表達(dá)式是惰性求值
- 默認(rèn)值可以引用解構(gòu)賦值的其他變量因谎,但該變量必須已經(jīng)聲明
對(duì)象的解構(gòu)賦值
- 簡(jiǎn)介
- 對(duì)象的解構(gòu)與數(shù)組有一個(gè)重要的不同。數(shù)組的元素是按次序排列的颜懊,變量的取值由它的位置決定财岔;而對(duì)象的屬性沒有次序,變量必須與屬性同名河爹,才能取到正確的值
- 如果解構(gòu)失敗匠璧,變量的值等于undefined
- 將Math對(duì)象的對(duì)數(shù)、正弦咸这、余弦三個(gè)方法夷恍,賦值到對(duì)應(yīng)的變量上,使用起來(lái)就會(huì)方便很多
let { log, sin, cos } = Math;
- 如果變量名與屬性名不一致炊苫,必須寫成下面這樣
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
- 對(duì)象的解構(gòu)賦值可以取到繼承的屬性
- 解構(gòu)也可以用于嵌套結(jié)構(gòu)的對(duì)象
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
- 注意裁厅,這時(shí)p是模式冰沙,不是變量侨艾,因此不會(huì)被賦值。如果p也要作為變量賦值拓挥,可以寫成下面這樣唠梨。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
- 默認(rèn)值
- 對(duì)象的解構(gòu)也可以指定默認(rèn)值
- 默認(rèn)值生效的條件是,對(duì)象的屬性值嚴(yán)格等于undefined
- 注意點(diǎn)
- 如果要將一個(gè)已經(jīng)聲明的變量用于解構(gòu)賦值侥啤,必須非常小心
- 解構(gòu)賦值允許等號(hào)左邊的模式之中当叭,不放置任何變量名茬故。因此,可以寫出非常古怪的賦值表達(dá)式
- 由于數(shù)組本質(zhì)是特殊的對(duì)象蚁鳖,因此可以對(duì)數(shù)組進(jìn)行對(duì)象屬性的解構(gòu)
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;//方括號(hào)這種寫法磺芭,屬于“屬性名表達(dá)式”
first // 1
last // 3
- 字符串的解構(gòu)賦值
- 字符串也可以解構(gòu)賦值。這是因?yàn)榇藭r(shí)醉箕,字符串被轉(zhuǎn)換成了一個(gè)類似數(shù)組的對(duì)象
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
- 類似數(shù)組的對(duì)象都有一個(gè)length屬性钾腺,因此還可以對(duì)這個(gè)屬性解構(gòu)賦值
let {length : len} = 'hello';
len // 5
- 數(shù)值和布爾值的解構(gòu)賦值
- 解構(gòu)賦值的規(guī)則是,只要等號(hào)右邊的值不是對(duì)象或數(shù)組讥裤,就先將其轉(zhuǎn)為對(duì)象放棒。由于undefined和null無(wú)法轉(zhuǎn)為對(duì)象,所以對(duì)它們進(jìn)行解構(gòu)賦值己英,都會(huì)報(bào)錯(cuò)
- 函數(shù)參數(shù)的解構(gòu)賦值
- undefined就會(huì)觸發(fā)函數(shù)參數(shù)的默認(rèn)值
- 圓括號(hào)問題
- es6規(guī)則:只要有可能導(dǎo)致解構(gòu)的歧義间螟,就不得使用圓括號(hào);阮一峰建議只要有可能损肛,就不要在模式中放置圓括號(hào)
- 不能使用圓括號(hào)的情況
- 變量聲明語(yǔ)句
// 全部報(bào)錯(cuò)
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
- 函數(shù)參數(shù)
// 報(bào)錯(cuò)
function f([(z)]) { return z; }
// 報(bào)錯(cuò)
function f([z,(x)]) { return x; }
- 賦值語(yǔ)句的模式
- 可以使用圓括號(hào)的情況
- 賦值語(yǔ)句的非模式部分厢破,可以使用圓括號(hào)
- 用途
- 交換變量的值
- 從函數(shù)返回多個(gè)值
- 函數(shù)參數(shù)的定義
- JSON數(shù)據(jù)的提取
- 函數(shù)參數(shù)的默認(rèn)值
- 遍歷map數(shù)組
- 任何部署了 Iterator 接口的對(duì)象,都可以用for...of循環(huán)遍歷荧关。Map 結(jié)構(gòu)原生支持 Iterator 接口溉奕,配合變量的解構(gòu)賦值,獲取鍵名和鍵值就非常方便忍啤。
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
- 如果只想獲取鍵名加勤,或者只想獲取鍵值,可以寫成下面這樣同波。
// 獲取鍵名
for (let [key] of map) {
// ...
}
// 獲取鍵值
for (let [,value] of map) {
// ...
}
- 輸入模塊的指定方法
class表達(dá)式
與函數(shù)一樣鳄梅,類也可以使用表達(dá)式的形式定義
const myClass = new Me{
getClassName(){
return Me.name;
}
}
set
var s = new set();
s.add()
不會(huì)添加重復(fù)值
Set函數(shù)可以接受一個(gè)數(shù)組(或者具有 iterable 接口的其他數(shù)據(jù)結(jié)構(gòu))作為參數(shù),用來(lái)初始化
set可以可以去重(包括NaN)
兩個(gè)對(duì)象總是不相等的
Set結(jié)構(gòu)實(shí)例有一下屬性:
Set.prototype.constructor:構(gòu)造函數(shù)未檩,默認(rèn)就是Set函數(shù)戴尸。
Set.prototype.size:返回Set實(shí)例的成員總數(shù)。
Set實(shí)例分為兩大類冤狡,操作方法和遍歷方法
Set.prototype.add(value):添加某個(gè)值孙蒙,返回 Set 結(jié)構(gòu)本身。
Set.prototype.delete(value):刪除某個(gè)值悲雳,返回一個(gè)布爾值挎峦,表示刪除是否成功。
Set.prototype.has(value):返回一個(gè)布爾值合瓢,表示該值是否為Set的成員坦胶。
Set.prototype.clear():清除所有成員,沒有返回值。
Array.from方法可以將 Set 結(jié)構(gòu)轉(zhuǎn)為數(shù)組
數(shù)組去重:Array.from(new Set(array))
Set.prototype.keys():返回鍵名的遍歷器
Set.prototype.values():返回鍵值的遍歷器
Set.prototype.entries():返回鍵值對(duì)的遍歷器
Set.prototype.forEach():使用回調(diào)函數(shù)遍歷每個(gè)成員
for of;map;filter;
因此使用 Set 可以很容易地實(shí)現(xiàn)并集(Union)顿苇、交集(Intersect)和差集(Difference)峭咒。
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
map
ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu)。它類似于對(duì)象纪岁,也是鍵值對(duì)的集合凑队,但是“鍵”的范圍不限于字符串,各種類型的值(包括對(duì)象)都可以當(dāng)作鍵
Set和Map都可以用來(lái)生成新的 Map
size 屬性
Map.prototype.set(key, value)
Map.prototype.get(key)
Map.prototype.has(key)
Map.prototype.delete(key)
Map.prototype.clear()
Map.prototype.keys():返回鍵名的遍歷器幔翰。
Map.prototype.values():返回鍵值的遍歷器顽决。
Map.prototype.entries():返回所有成員的遍歷器。
Map.prototype.forEach():遍歷 Map 的所有成員
iterator
1. Iterator(遍歷器)的概念
- 遍歷器(Iterator)就是這樣一種機(jī)制导匣。它是一種接口才菠,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問機(jī)制。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口贡定,就可以完成遍歷操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)
- Iterator 的作用有三個(gè):一是為各種數(shù)據(jù)結(jié)構(gòu)赋访,提供一個(gè)統(tǒng)一的、簡(jiǎn)便的訪問接口缓待;二是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列蚓耽;三是 ES6 創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator 接口主要供for...of消費(fèi)
- Iterator 的遍歷過程是這樣的
(1)創(chuàng)建一個(gè)指針對(duì)象旋炒,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置步悠。也就是說(shuō),遍歷器對(duì)象本質(zhì)上瘫镇,就是一個(gè)指針對(duì)象鼎兽。
(2)第一次調(diào)用指針對(duì)象的next方法,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員铣除。
(3)第二次調(diào)用指針對(duì)象的next方法谚咬,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個(gè)成員。
(4)不斷調(diào)用指針對(duì)象的next方法尚粘,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置择卦。
每一次調(diào)用next方法,都會(huì)返回?cái)?shù)據(jù)結(jié)構(gòu)的當(dāng)前成員的信息郎嫁。具體來(lái)說(shuō)秉继,就是返回一個(gè)包含value和done兩個(gè)屬性的對(duì)象。其中泽铛,value屬性是當(dāng)前成員的值尚辑,done屬性是一個(gè)布爾值,表示遍歷是否結(jié)束厚宰。
2. 默認(rèn) Iterator 接口
3. 調(diào)用 Iterator 接口的場(chǎng)合
4. 字符串的 Iterator 接口
5. Iterator 接口與 Generator 函數(shù)
6. 遍歷器對(duì)象的 return()腌巾,throw()
7. for...of 循環(huán)
promise
1.Promise的含義
- Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強(qiáng)大
- 所謂Promise铲觉,簡(jiǎn)單說(shuō)就是一個(gè)容器澈蝙,里面保存著某個(gè)未來(lái)才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語(yǔ)法上說(shuō)撵幽,Promise 是一個(gè)對(duì)象灯荧,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API盐杂,各種異步操作都可以用同樣的方法進(jìn)行處理
- Promise對(duì)象有以下兩個(gè)特點(diǎn)逗载。
- 對(duì)象的狀態(tài)不受外界影響。Promise對(duì)象代表一個(gè)異步操作链烈,有三種狀態(tài):pending(進(jìn)行中)厉斟、fulfilled(已成功)和rejected(已失敗)强衡。只有異步操作的結(jié)果擦秽,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無(wú)法改變這個(gè)狀態(tài)漩勤。這也是Promise這個(gè)名字的由來(lái)感挥,它的英語(yǔ)意思就是“承諾”,表示其他手段無(wú)法改變越败。
- 一旦狀態(tài)改變触幼,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果究飞。Promise對(duì)象的狀態(tài)改變置谦,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生亿傅,狀態(tài)就凝固了霉祸,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果袱蜡,這時(shí)就稱為 resolved(已定型)丝蹭。如果改變已經(jīng)發(fā)生了,你再對(duì)Promise對(duì)象添加回調(diào)函數(shù)坪蚁,也會(huì)立即得到這個(gè)結(jié)果奔穿。這與事件(Event)完全不同,事件的特點(diǎn)是敏晤,如果你錯(cuò)過了它贱田,再去監(jiān)聽,是得不到結(jié)果的嘴脾。
- Promise也有一些缺點(diǎn)男摧。首先蔬墩,無(wú)法取消Promise,一旦新建它就會(huì)立即執(zhí)行耗拓,無(wú)法中途取消拇颅。其次,如果不設(shè)置回調(diào)函數(shù)乔询,Promise內(nèi)部拋出的錯(cuò)誤樟插,不會(huì)反應(yīng)到外部。第三竿刁,當(dāng)處于pending狀態(tài)時(shí)黄锤,無(wú)法得知目前進(jìn)展到哪一個(gè)階段
2.基本用法
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 異步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
- Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject食拜。它們是兩個(gè)函數(shù)鸵熟,由 JavaScript 引擎提供,不用自己部署
- resolve函數(shù)的作用是负甸,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved)旅赢,在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果惑惶,作為參數(shù)傳遞出去
- reject函數(shù)的作用是煮盼,將Promise對(duì)象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用带污,并將異步操作報(bào)出的錯(cuò)誤僵控,作為參數(shù)傳遞出去
- Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)
promise.then(function(value) {
// success
}, function(error) {
// failure
});
- then方法可以接受兩個(gè)回調(diào)函數(shù)作為參數(shù)鱼冀。第一個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用报破,第二個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用。其中千绪,第二個(gè)函數(shù)是可選的充易,不一定要提供。這兩個(gè)函數(shù)都接受Promise對(duì)象傳出的值作為參數(shù)
- Promise 新建后就會(huì)立即執(zhí)行荸型。
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
});
promise.then(function() {
console.log('resolved.');
});
console.log('Hi!');
// Promise
// Hi!
// resolved
- Promise 新建后立即執(zhí)行盹靴,所以首先輸出的是Promise。然后瑞妇,then方法指定的回調(diào)函數(shù)稿静,將在當(dāng)前腳本所有同步任務(wù)執(zhí)行完才會(huì)執(zhí)行,所以resolved最后輸出
- resolve函數(shù)的參數(shù)除了正常的值以外辕狰,還可能是另一個(gè) Promise
const p1 = new Promise(function (resolve, reject) {
// ...
});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})
- p1和p2都是 Promise 的實(shí)例改备,但是p2的resolve方法將p1作為參數(shù),即一個(gè)異步操作的結(jié)果是返回另一個(gè)異步操作
- 注意蔓倍,這時(shí)p1的狀態(tài)就會(huì)傳遞給p2悬钳,也就是說(shuō)盐捷,p1的狀態(tài)決定了p2的狀態(tài)。如果p1的狀態(tài)是pending默勾,那么p2的回調(diào)函數(shù)就會(huì)等待p1的狀態(tài)改變碉渡;如果p1的狀態(tài)已經(jīng)是resolved或者rejected,那么p2的回調(diào)函數(shù)將會(huì)立刻執(zhí)行
3.Promise.prototype.then()
- Promise 實(shí)例具有then方法,是定義在原型對(duì)象Promise.prototype上的,它的作用是為 Promise 實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)灾测。then方法的第一個(gè)參數(shù)是resolved狀態(tài)的回調(diào)函數(shù),第二個(gè)參數(shù)(可選)是rejected狀態(tài)的回調(diào)函數(shù)垦巴,then方法返回的是一個(gè)新的Promise實(shí)例(注意媳搪,不是原來(lái)那個(gè)Promise實(shí)例),因此可以采用鏈?zhǔn)綄懛ㄖ栊磘hen方法后面再調(diào)用另一個(gè)then方法
4.Promise.prototype.catch()
- Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的別名秦爆,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
//等同于
promise.catch(function(error) {
console.log(error);
});
// Error: test
// 寫法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
promise.catch(function(error) {
console.log(error);
});
// 寫法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
- 比較上面兩種寫法,可以發(fā)現(xiàn)reject方法的作用憔披,等同于拋出錯(cuò)誤等限。
- 如果 Promise 狀態(tài)已經(jīng)變成resolved,再拋出錯(cuò)誤是無(wú)效的
- Promise 對(duì)象的錯(cuò)誤具有“冒泡”性質(zhì)芬膝,會(huì)一直向后傳遞望门,直到被捕獲為止。也就是說(shuō)锰霜,錯(cuò)誤總是會(huì)被下一個(gè)catch語(yǔ)句捕獲
- 一般來(lái)說(shuō)筹误,不要在then方法里面定義 Reject 狀態(tài)的回調(diào)函數(shù)(即then的第二個(gè)參數(shù)),總是使用catch方法
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
- 第二種寫法要好于第一種寫法癣缅,理由是第二種寫法可以捕獲前面then方法執(zhí)行中的錯(cuò)誤厨剪,也更接近同步的寫法(try/catch)。因此友存,建議總是使用catch方法祷膳,而不使用then方法的第二個(gè)參數(shù)
5.Promise.prototype.finally()
- inally方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的操作
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
- 不管promise最后的狀態(tài)屡立,在執(zhí)行完then或catch指定的回調(diào)函數(shù)以后直晨,都會(huì)執(zhí)行finally方法指定的回調(diào)函數(shù)
- finally方法的回調(diào)函數(shù)不接受任何參數(shù),這意味著沒有辦法知道膨俐,前面的 Promise 狀態(tài)到底是fulfilled還是rejected抡秆。這表明,finally方法里面的操作吟策,應(yīng)該是與狀態(tài)無(wú)關(guān)的儒士,不依賴于 Promise 的執(zhí)行結(jié)果
6.Promise.all()
- Promise.all方法用于將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例
const p = Promise.all([p1, p2, p3]);
- Promise.all方法接受一個(gè)數(shù)組作為參數(shù)檩坚,p1着撩、p2诅福、p3都是 Promise 實(shí)例,如果不是拖叙,就會(huì)先調(diào)用下面講到的Promise.resolve方法氓润,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理薯鳍。(Promise.all方法的參數(shù)可以不是數(shù)組咖气,但必須具有 Iterator 接口,且返回的每個(gè)成員都是 Promise 實(shí)例挖滤。)
- p的狀態(tài)由p1崩溪、p2、p3決定斩松,分成兩種情況伶唯。
- (1)只有p1、p2惧盹、p3的狀態(tài)都變成fulfilled乳幸,p的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1钧椰、p2粹断、p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)嫡霞;(2)只要p1姿染、p2、p3之中有一個(gè)被rejected秒际,p的狀態(tài)就變成rejected悬赏,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)
7.Promise.race()
- Promise.race方法同樣是將多個(gè) Promise 實(shí)例娄徊,包裝成一個(gè)新的 Promise 實(shí)例
- 上面代碼中闽颇,只要p1、p2寄锐、p3之中有一個(gè)實(shí)例率先改變狀態(tài)兵多,p的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值橄仆,就傳遞給p的回調(diào)函數(shù)
8.Promise.resolve()
- 有時(shí)需要將現(xiàn)有對(duì)象轉(zhuǎn)為 Promise 對(duì)象剩膘,Promise.resolve方法就起到這個(gè)作用
- Promise.resolve方法的參數(shù)分成四種情況。
參數(shù)是一個(gè) Promise 實(shí)例
- 如果參數(shù)是 Promise 實(shí)例盆顾,那么Promise.resolve將不做任何修改怠褐、原封不動(dòng)地返回這個(gè)實(shí)例。
參數(shù)是一個(gè)thenable對(duì)象
- thenable對(duì)象指的是具有then方法的對(duì)象您宪,比如下面這個(gè)對(duì)象奈懒。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
- Promise.resolve方法會(huì)將這個(gè)對(duì)象轉(zhuǎn)為 Promise 對(duì)象奠涌,然后就立即執(zhí)行thenable對(duì)象的then方法。
- 參數(shù)不是具有then方法的對(duì)象磷杏,或根本就不是對(duì)象
- 如果參數(shù)是一個(gè)原始值溜畅,或者是一個(gè)不具有then方法的對(duì)象,則Promise.resolve方法返回一個(gè)新的 Promise 對(duì)象极祸,狀態(tài)為resolved慈格。
- 不帶有任何參數(shù)
- Promise.resolve()方法允許調(diào)用時(shí)不帶參數(shù),直接返回一個(gè)resolved狀態(tài)的 Promise 對(duì)象遥金,所以浴捆,如果希望得到一個(gè) Promise 對(duì)象,比較方便的方法就是直接調(diào)用Promise.resolve()方法汰规。
9.Promise.reject()
- Promise.reject(reason)方法也會(huì)返回一個(gè)新的 Promise 實(shí)例汤功,該實(shí)例的狀態(tài)為rejected
- 注意物邑,Promise.reject()方法的參數(shù)溜哮,會(huì)原封不動(dòng)地作為reject的理由,變成后續(xù)方法的參數(shù)
10.應(yīng)用
- 異步加載圖片
function loadImageAsync(url) {
return new Promise(function(resolve, reject) {
const image = new Image();
image.onload = function() {
resolve(image);
};
image.onerror = function() {
reject(new Error('Could not load image at ' + url));
};
image.src = url;
});
}
- Ajax 操作
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出錯(cuò)了', error);
});
- getJSON是對(duì) XMLHttpRequest 對(duì)象的封裝色解,用于發(fā)出一個(gè)針對(duì) JSON 數(shù)據(jù)的 HTTP 請(qǐng)求茂嗓,并且返回一個(gè)Promise對(duì)象。需要注意的是科阎,在getJSON內(nèi)部述吸,resolve函數(shù)和reject函數(shù)調(diào)用時(shí),都帶有參數(shù)锣笨。如果調(diào)用resolve函數(shù)和reject函數(shù)時(shí)帶有參數(shù)蝌矛,那么它們的參數(shù)會(huì)被傳遞給回調(diào)函數(shù)。reject函數(shù)的參數(shù)通常是Error對(duì)象的實(shí)例错英,表示拋出的錯(cuò)誤