前言
大家好,首先表明一下,標題沒有惡意哈哈。請原諒本菜雞。都是為了幫助大家,大家可以把自己認識幾個,得了多少分,發在留言裡,一個一分,總分38分。
大家好,我是林三心,這段時間很多兄弟姐妹都來問我問題,我也看過很多他們的程式碼。給我的感覺就是,程式碼的使用還停留在了ES5的那個階段,很多用新語法就能輕鬆實現的,卻都不怎麼了解,所以我就打算寫一篇文章,總結一下在我工作中用過的非常實用的ES6,ES7,ES8,ES9,ES10,ES11,ES12
語法。
首先說明一下:我這裡只是舉了最基礎的例子,但是專案中要怎麼去靈活運用,這個就要各位同學自己去摸索了。
ES6
1、let 和 const
這兩個的出現,總感覺是為了開發的程式碼規範而出現的。我們要逐漸放棄var,在專案中多用let和const
與var的區別:
- var有變數提升,有初始化提升,值可變
- let有變數提升,沒有初始化提升,值可變
- const有變數提升,沒有初始化提升,值不可變,但如果是定義物件,則屬性可變
暫時性死區
問題說明:其實let和const
是有變數提升的,但是沒有初始化提升:
var name = '林三心'
function fn () {
console.log(name)
let name = 'sunshin_lin'
}
fn() // Cannot access 'name' before initialization
塊級作用域解決問題:
for(var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i)
})
} // 5 5 5 5 5
for(let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i)
})
} // 0 1 2 3 4
2、預設引數
開發中你曾遇到過這樣的問題,如果引數不傳進來,你就設定預設引數
function fn (name, age) {
var name = name || '林三心'
var age = age || 18
console.log(name, age)
}
fn() // 林三心 18
但是這麼寫確實不優雅,可以使用ES6的預設引數
function fn (name = '林三心', age = 18) {
console.log(name, age)
}
fn() // 林三心 18
fn('sunshine', 22) // sunshine 22
3、擴充套件運算子
曾經的我,想要拼接多個陣列,我只能這麼做
const arr1 = [1, 2, 4]
const arr2 = [4, 5, 7]
const arr3 = [7, 8, 9]
const arr = arr1.concat(arr2).concat(arr3)
[
1, 2, 4, 4, 5,
7, 7, 8, 9
]
現在的我,可以更優雅地進行拼接
const arr1 = [1, 2, 4]
const arr2 = [4, 5, 7]
const arr3 = [7, 8, 9]
const arr = [...arr1, ...arr2, ...arr3]
[
1, 2, 4, 4, 5,
7, 7, 8, 9
]
4、剩餘引數
大家可能遇到過這種問題,一個函式,傳入引數的個數是不確定的,這就可以用ES6的剩餘引數
function fn (name, ...params) {
console.log(name)
console.log(params)
}
fn ('林三心', 1, 2) // 林三心 [ 1, 2 ]
fn ('林三心', 1, 2, 3, 4, 5) // 林三心 [ 1, 2, 3, 4, 5 ]
5、模板字串
以前的我,拼接字串只能這麼做
const name = '林三心'
const age = '22'
console.log(name + '今年' + age + '歲啦') // 林三心今年22歲啦
現在我可以這麼做,會更優雅
const name = '林三心'
const age = '22'
console.log(`${name}今年${age}歲啦`) // 林三心今年22歲啦
6、Object.keys
可以用來獲取物件的key的集合,進而可以獲得對應key的value
const obj = {
name: '林三心',
age: 22,
gender: '男'
}
const keys = Object.keys(obj)
console.log(keys) // [ 'name', 'age', 'gender' ]
7、箭頭函式
以前我們使用普通函式
function fn () {}
const fn = function () {}
ES6新加了箭頭函式
const fn = () => {}
// 如果只有一個引數,可以省略括號
const fn = name => {}
// 如果函式體裡只有一句return
const fn = name => {
return 2 * name
}
// 可簡寫為
const fn = name => 2 * name
// 如果返回的是物件
const fn = name => ({ name: name })
普通函式和箭頭函式的區別:
- 1、箭頭函式不可作為建構函式,不能使用new
- 2、箭頭函式沒有自己的this
- 3、箭頭函式沒有arguments物件
- 4、箭頭函式沒有原型物件
8、Array.prototype.forEach
ES6新加的陣列遍歷方法
const eachArr = [1, 2, 3, 4, 5]
// 三個引數:遍歷項 索引 陣列本身
// 配合箭頭函式
eachArr.forEach((item, index, arr) => {
console.log(item, index, arr)
})
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
9、Array.prototype.map
常用於返回一個處理過後的新陣列
const mapArr = [1, 2, 3, 4, 5]
// 三個引數:遍歷項 索引 陣列本身
// 配合箭頭函式,對每一個元素進行翻倍
const mapArr2 = mapArr.map((num, index, arr) => 2 * num)
console.log(mapArr2)
[ 2, 4, 6, 8, 10 ]
10、Array.prototype.filter
顧名思義,用來過濾的方法
const filterArr = [1, 2, 3, 4, 5]
// 三個引數:遍歷項 索引 陣列本身
// 配合箭頭函式,返回大於3的集合
const filterArr2 = filterArr.filter((num, index, arr) => num > 3)
console.log(filterArr2)
[ 4, 5 ]
11、Array.prototype.some
some,意思就是隻要有一個是真,那就返回真
const someArr = [false, true, false, true, false]
// 三個引數:遍歷項 索引 陣列本身
// 配合箭頭函式,只要有一個為true,就返回true,一個都true都沒有,就返回false
const someArr2 = someArr.some((bol, index, arr) => bol)
console.log(someArr2)
true
12、Array.prototype.every
every跟some是相反的,some是隻要有一個就行,every是要所有為真才返回真
const everyArr = [false, true, false, true, false]
// 三個引數:遍歷項 索引 陣列本身
// 配合箭頭函式,需要所有為true,才返回true,否則返回false
const everyArr2 = everyArr.every((bol, index, arr) => bol)
console.log(everyArr2)
13、Array.prototype.reduce
- 第一個引數callback函式: pre為上次return的值,next為陣列的本次遍歷的項
- 第二個引數為初始值,也是第一個pre
舉兩個例子:
// 計算 1 + 2 + 3 + 4 + 5
const reduceArr = [1, 2, 3, 4, 5]
const sum = reduceArr.reduce((pre, next) => {
return pre + next
}, 0)
console.log(sum) // 15
// 統計元素出現個數
const nameArr = ['林三心', 'sunshine_lin', '林三心', '林三心', '科比']
const totalObj = nameArr.reduce((pre, next) => {
if (pre[next]) {
pre[next]++
} else {
pre[next] = 1
}
return pre
}, {})
console.log(totalObj) // { '林三心': 3, sunshine_lin: 1, '科比': 1 }
14、物件屬性同名簡寫
以前同名屬性需要這麼寫
const name = '林三心'
const age = '22'
const obj = {
name: name,
age: age
}
console.log(obj) // { name: '林三心', age: '22' }
ES6新增語法,只需這麼寫
const name = '林三心'
const age = '22'
// 屬性同名可簡寫
const obj = {
name,
age
}
console.log(obj) // { name: '林三心', age: '22' }
15、Promise
Promise
,中文名為承諾
,承諾在哪呢?承諾在,一旦他的狀態改變,就不會再改。這裡就介紹基本使用,如果想要深入理解如何使用,請看我的另一篇文章看了就會,手寫Promise原理,最通俗易懂的版本!!!
看看基本使用
成功狀態
function requestData () { // 模擬請求 return new Promise((resolve, reject) => { setTimeout(() => { resolve('林三心') }, 1000) }) } requestData().then(res => { console.log(res) // 一秒鐘後輸出 '林三心' }, err => { console.log(err) })
失敗狀態
function requestData () { // 模擬請求 return new Promise((resolve, reject) => { setTimeout(() => { reject('錯誤啦') }, 1000) }) } requestData().then(res => { console.log(res) }, err => { console.log(err) // 一秒鐘後輸出 '錯誤啦' })
all
方法- 接收一個Promise陣列,陣列中如有非Promise項,則此項當做成功
- 如果所有Promise都成功,則返回成功結果陣列
- 如果有一個Promise失敗,則返回這個失敗結果
// 如果全都為成功 function fn(time) { return new Promise((resolve, reject) => { console.log(88) setTimeout(() => { resolve(`${time}毫秒後我成功啦!!!`) }, time) }) } Promise.all([fn(2000), fn(3000), fn(1000)]).then(res => { // 3秒後輸出 [ '2000毫秒後我成功啦!!!', '3000毫秒後我成功啦!!!', '1000毫秒後我成功啦!!!' ] console.log(res) }, err => { console.log(err) }) // 如果有一個失敗 function fn(time, isResolve) { return new Promise((resolve, reject) => { setTimeout(() => { isResolve ? resolve(`${time}毫秒後我成功啦!!!`) : reject(`${time}毫秒後我失敗啦!!!`) }, time) }) } Promise.all([fn(2000, true), fn(3000), fn(1000, true)]).then(res => { console.log(res) }, err => { console.log(err) // 3秒後輸出 '3000毫秒後我失敗啦!!!' })
race
方法- 接收一個Promise陣列,陣列中如有非Promise項,則此項當做成功
- 哪個Promise最快得到結果,就返回那個結果,無論成功失敗
function fn(time, isResolve) { return new Promise((resolve, reject) => { setTimeout(() => { isResolve ? resolve(`${time}毫秒後我成功啦!!!`) : reject(`${time}毫秒後我失敗啦!!!`) }, time) }) } Promise.race([fn(2000, true), fn(3000), fn(1000)]).then(res => { console.log(res) }, err => { console.log(err) // 1秒後輸出 })
16、class
以前我們們使用建構函式生成物件,這麼做
function Person(name) {
this.name = name
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const kobe = new Person('科比')
kobe.sayName() // 科比
而有了ES6的class
可以這麼做
class Person {
constructor(name) {
// 構造器
this.name = name
}
sayName() {
console.log(this.name)
}
}
const kobe = new Person('科比')
kobe.sayName() // 科比
值得一提的是,class
本質也是function
,class
是function
的語法糖
class Person {}
console.log(typeof Person) // function
除了以上,還需要知道class的以下知識點
靜態屬性和靜態方法,使用static
定義的屬性和方法只能class自己用,例項用不了
class Person {
constructor(name) {
this.name = name
}
static age = 22
static fn() {
console.log('哈哈')
}
}
console.log(Person.age) // 22
Person.fn() // 哈哈
const sunshine_lin = new Person('林三心')
console.log(sunshine_lin.age) // undefined
sunshine_lin.fn() // fn is not a function
extend
繼承
class Animal {
constructor(name, age) {
this.name = name
this.age = age
}
}
class Cat extends Animal {
say() {
console.log(this.name, this.age)
}
}
const cat = new Cat('ketty', 5) // 繼承了Animal的構造器
cat.say() // ketty 5
17、解構賦值
以前想提取物件裡的屬性需要這麼做
const obj = {
name: '林三心',
age: 22,
gender: '男'
}
const name = obj.name
const age = obj.age
const gender = obj.gender
console.log(name, age, gender) // 林三心 22 男
ES6新增瞭解構賦值的語法
const obj = {
name: '林三心',
age: 22,
gender: '男',
doing: {
morning: '摸魚',
afternoon: '摸魚',
evening: 'sleep'
}
}
const { name, age, gender } = obj
console.log(name, age, gender) // 林三心 22 男
// 解構重名
const { name: myname } = obj
console.log(myname) // 林三心
// 巢狀解構
const { doing: { evening } } = obj
console.log(evening) // sleep
也可以進行陣列的解構
const arr = [1, 2, 3]
const [a, b, c] = arr
console.log(a, b, c) // 1 2 3
// 預設賦值
const [a, b, c, d = 5] = arr
console.log(a, b, c, d) // 1 2 3 5
// 亂序解構
const { 1: a, 0: b, 2: c } = arr
console.log(a, b, c) // 2 1 3
18、find 和 findIndex
- find:找到返回被找元素,找不到返回undefined
findIndex:找到返回被找元素索引,找不到返回-1
const findArr = [ { name: '科比', no: '24' }, { name: '羅斯', no: '1' }, { name: '利拉德', no: '0' } ] const kobe = findArr.find(({ name }) => name === '科比') const kobeIndex = findArr.findIndex(({ name }) => name === '科比') console.log(kobe) // { name: '科比', no: '24' } console.log(kobeIndex) // 0
19、for of 和 for in
- for in :遍歷方法,可遍歷物件和陣列
for of :遍歷方法,只能遍歷陣列,不能遍歷非iterable物件
先看for in:const obj = { name: '林三心', age: 22, gender: '男' } const arr = [1, 2, 3, 4, 5] for(let key in obj) { console.log(key) } name age gender for(let index in arr) { console.log(index)
1 2 3 4
再看 for of:
for(let item of arr) {
console.log(item)
}2 3 4 5
Set
先說說Set
的基本用法// 可不傳陣列 const set1 = new Set() set1.add(1) set1.add(2) console.log(set1) // Set(2) { 1, 2 } // 也可傳陣列 const set2 = new Set([1, 2, 3]) // 增加元素 使用 add set2.add(4) set2.add('林三心') console.log(set2) // Set(5) { 1, 2, 3, 4, '林三心' } // 是否含有某個元素 使用 has console.log(set2.has(2)) // true // 檢視長度 使用 size console.log(set2.size) // 5 // 刪除元素 使用 delete set2.delete(2) console.log(set2) // Set(4) { 1, 3, 4, '林三心' }
再說說
Set
的不重複性// 增加一個已有元素,則增加無效,會被自動去重 const set1 = new Set([1]) set1.add(1) console.log(set1) // Set(1) { 1 } // 傳入的陣列中有重複項,會自動去重 const set2 = new Set([1, 2, '林三心', 3, 3, '林三心']) console.log(set2) // Set(4) { 1, 2, '林三心', 3 }
Set
的不重複性中,要注意引用資料型別和NaN
// 兩個物件都是不同的指標,所以沒法去重 const set1 = new Set([1, {name: '林三心'}, 2, {name: '林三心'}]) console.log(set1) // Set(4) { 1, { name: '林三心' }, 2, { name: '林三心' } } // 如果是兩個物件是同一指標,則能去重 const obj = {name: '林三心'} const set2 = new Set([1, obj, 2, obj]) console.log(set2) // Set(3) { 1, { name: '林三心' }, 2 } 我們們都知道 NaN !== NaN,NaN是自身不等於自身的,但是在Set中他還是會被去重 const set = new Set([1, NaN, 1, NaN]) console.log(set) // Set(2) { 1, NaN }
利用Set的不重複性,可以實現陣列去重
const arr = [1, 2, 3, 4, 4, 5, 5, 66, 9, 1] // Set可利用擴充套件運算子轉為陣列哦 const quchongArr = [...new Set(arr)] console.log(quchongArr) // [1, 2, 3, 4, 5, 66, 9]
Map
Map
對比object
最大的好處就是,key不受型別限制
// 定義map const map1 = new Map() // 新增鍵值對 使用 set(key, value) map1.set(true, 1) map1.set(1, 2) map1.set('哈哈', '嘻嘻嘻') console.log(map1) // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' } // 判斷map是否含有某個key 使用 has(key) console.log(map1.has('哈哈')) // true // 獲取map中某個key對應的value 使用 get(key) console.log(map1.get(true)) // 2 // 刪除map中某個鍵值對 使用 delete(key) map1.delete('哈哈') console.log(map1) // Map(2) { true => 1, 1 => 2 } // 定義map,也可傳入鍵值對陣列集合 const map2 = new Map([[true, 1], [1, 2], ['哈哈', '嘻嘻嘻']]) console.log(map2) // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' }
ES7
21、includes
傳入元素,如果陣列中能找到此元素,則返回true,否則返回false
const includeArr = [1, 2 , 3, '林三心', '科比'] const isKobe = includeArr.includes('科比') console.log(isKobe) // true
跟indexOf很像,但還是有區別的
const arr = [1, 2, NaN]
console.log(arr.indexOf(NaN)) // -1 indexOf找不到NaN
console.log(arr.includes(NaN)) // true includes能找到NaN
22、求冪運算子
以前求冪,我們需要這麼寫
const num = Math.pow(3, 2) // 9
ES7提供了求冪運算子:**
const num = 3 ** 2 // 9
ES8
23、Object.values
可以用來獲取物件的value的集合
const obj = {
name: '林三心',
age: 22,
gender: '男'
}
const values = Object.values(obj)
console.log(values) // [ '林三心', 22, '男' ]
24、Object.entries
可以用來獲取物件的鍵值對集合
const obj = {
name: '林三心',
age: 22,
gender: '男'
}
const entries = Object.entries(obj)
console.log(entries)
// [ [ 'name', '林三心' ], [ 'age', 22 ], [ 'gender', '男' ] ]
25、async/await
這個是很常用的語法了,我的理解就是:以同步方式執行非同步操作
我們平時可能會遇到這種場景,介面一,請求到資料一,而資料一被當做請求二的引數去請求資料二,我們會用Promise這麼做
function fn() {
// 模擬第一次請求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5)
}, 1000)
}).then(res => {
// 模擬第二次請求
new Promise((resolve, reject) => {
setTimeout(() => {
// 拿第一次請求的資料去乘10,當做第二次請求的資料
resolve(res * 10)
}, 2000)
}).then(sres => {
console.log(sres)
})
})
}
fn() // 1 + 2 = 3 3秒後輸出 50
這樣的巢狀是不美觀的,如果有很多個介面,那就會巢狀很多層,此時我們可以使用async/await來以同步方式執行非同步,注意以下幾點:
- await只能在async函式裡使用
- await後面最好接Promise,如果後面接的是普通函式則會直接執行
async函式返回的是一個Promise
function fn1 () { return new Promise((resolve, reject) => { setTimeout(() => { resolve(5) }, 1000) }) } function fn2 (data) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(data * 10) }, 2000) }) } async function req () { // 同步方式執行非同步,像排隊一樣 const data1 = await fn1() // 等待1秒後返回資料再往下執行 const data2 = await fn2(data1) // 拿data1去請求2秒後,往下走 console.log(data2) // 總共3秒後 輸出 50 } req()
ES9
26、for await of
我們來看以下場景哈
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒後我成功啦!!!`)
}, time)
})
}
fn(3000).then(res => console.log(res))
fn(1000).then(res => console.log(res))
fn(2000).then(res => console.log(res))
結果是
1000毫秒後我成功啦!!!
2000毫秒後我成功啦!!!
3000毫秒後我成功啦!!!
但是我想要這個結果
3000毫秒後我成功啦!!!
1000毫秒後我成功啦!!!
2000毫秒後我成功啦!!!
第一時間我們肯定想到的是async/await
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒後我成功啦!!!`)
}, time)
})
}
async function asyncFn () {
// 排隊
const data1 = await fn(3000)
console.log(data1) // 3秒後 3000毫秒後我成功啦!!!
const data2 = await fn(1000)
console.log(data2) // 再過1秒 1000毫秒後我成功啦!!!
const data3 = await fn(2000)
console.log(data3) // 再過2秒 2000毫秒後我成功啦!!!
}
但是上面程式碼也是有缺點的,如果有幾十個,那不是得寫幾十個await,有沒有一種方法可以通過迴圈來輸出呢?
function fn (time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time}毫秒後我成功啦!!!`)
}, time)
})
}
async function asyncFn () {
const arr = [fn(3000), fn(1000), fn(1000), fn(2000), fn(500)]
for await (let x of arr) {
console.log(x)
}
}
asyncFn()
3000毫秒後我成功啦!!!
1000毫秒後我成功啦!!!
1000毫秒後我成功啦!!!
2000毫秒後我成功啦!!!
500毫秒後我成功啦!!!
27、Promise.finally
新增的Promise方法,無論失敗或者成功狀態,都會執行這個函式
// cheng
new Promise((resolve, reject) => {
resolve('成功嘍')
}).then(
res => { console.log(res) },
err => { console.log(err) }
).finally(() => { console.log('我是finally') })
new Promise((resolve, reject) => {
reject('失敗嘍')
}).then(
res => { console.log(res) },
err => { console.log(err) }
).finally(() => { console.log('我是finally') })
ES10
28、Array.flat
有一個二維陣列,我想讓他變成一維陣列:
const arr = [1, 2, 3, [4, 5, 6]]
console.log(arr.flat()) // [ 1, 2, 3, 4, 5, 6 ]
還可以傳引數,引數為降維的次數
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9]]]
console.log(arr.flat(2))
[
1, 2, 3, 4, 5,
6, 7, 8, 9
]
如果傳的是一個無限大的數字,那麼就實現了多維陣列(無論幾維)降為一維陣列
const arr = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]]
console.log(arr.flat(Infinity))
[
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12
]
29、Array.flatMap
現在給你一個需求
let arr = ["科比 詹姆斯 安東尼", "利拉德 羅斯 麥科勒姆"];
將上面陣列轉為
[ '科比', '詹姆斯', '安東尼', '利拉德', '羅斯', '麥科勒姆' ]
第一時間想到map + flat
console.log(arr.map(x => x.split(" ")).flat());
// [ '科比', '詹姆斯', '安東尼', '利拉德', '羅斯', '麥科勒姆' ]
flatMap
就是flat + map
,一個方法頂兩個
console.log(arr.flatMap(x => x.split(" ")));
// [ '科比', '詹姆斯', '安東尼', '利拉德', '羅斯', '麥科勒姆' ]
30、BigInt
BigInt
是ES10新加的一種JavaScript資料型別,用來表示表示大於 2^53 - 1
的整數,2^53 - 1
是ES10之前,JavaScript所能表示最大的數字
const theBiggestInt = 9007199254740991n;
const alsoHuge = BigInt(9007199254740991);
// 9007199254740991n
const hugeString = BigInt("9007199254740991");
// 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff");
// 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// 9007199254740991n
哦對了,既然是JavaScript新的資料型別,那他的typeof
是啥?
const bigNum = BigInt(1728371927189372189739217)
console.log(typeof bigNum) // bigint
所以以後面試官問你JavaScript有多少種資料型別,別傻傻答6種了,要答8種,把ES6的Symbol
和ES10的BigInt
也加上去
31、Object.fromEntries
前面ES8的Object.entries
是把物件轉成鍵值對陣列
,而Object.fromEntries
則相反,是把鍵值對陣列轉為物件
const arr = [
['name', '林三心'],
['age', 22],
['gender', '男']
]
console.log(Object.fromEntries(arr)) // { name: '林三心', age: 22, gender: '男' }
他還有一個用處,就是把Map轉為物件
const map = new Map()
map.set('name', '林三心')
map.set('age', 22)
map.set('gender', '男')
console.log(map) // Map(3) { 'name' => '林三心', 'age' => 22, 'gender' => '男' }
const obj = Object.fromEntries(map)
console.log(obj) // { name: '林三心', age: 22, gender: '男' }
32、String.trimStart && String.trimEnd
我們們都知道JavaScript有個trim方法,可以清除字串首尾的空格
const str = ' 林三心 '
console.log(str.trim()) // '林三心'
trimStart和trimEnd用來單獨去除字串的首和尾的空格
const str = ' 林三心 '
// 去除首部空格
console.log(str.trimStart()) // '林三心 '
// 去除尾部空格
console.log(str.trimEnd()) // ' 林三心'
ES11
33、Promise.allSettled
ES11新增的Promise的方法
- 接收一個Promise陣列,陣列中如有非Promise項,則此項當做成功
把每一個Promise的結果,集合成陣列,返回
function fn(time, isResolve) { return new Promise((resolve, reject) => { setTimeout(() => { isResolve ? resolve(`${time}毫秒後我成功啦!!!`) : reject(`${time}毫秒後我失敗啦!!!`) }, time) }) } Promise.allSettled([fn(2000, true), fn(3000), fn(1000)]).then(res => { console.log(res) // 3秒後輸出 [ { status: 'fulfilled', value: '2000毫秒後我成功啦!!!' }, { status: 'rejected', reason: '3000毫秒後我失敗啦!!!' }, { status: 'rejected', reason: '1000毫秒後我失敗啦!!!' } ] })
34、?. 和 ??
- 先說說
?.
,中文名為可選鏈
比如我們需要一個變數,是陣列且有長度,才做某些操作
const list = null
// do something
if (list && list.length) {
// do something
}
// 使用可選鏈
const list = null
// do something
if (list?.length) {
// do something
}
比如有一個物件,我要取一個可能不存在的值,甚至我們都不確定obj是否存在
const obj = {
cat: {
name: '哈哈'
}
}
const dog = obj && obj.dog && obj.dog.name // undefined
// 可選鏈
const obj = {
cat: {
name: '哈哈'
}
}
const dog = obj?.dog?.name // undefined
比如有一個陣列,我不確定它存不存在,存在的話就取索引為1的值
const arr = null
// do something
const item = arr && arr[1]
// 可選鏈
const arr = null
// do something
const item = arr?.[1]
比如有一個函式,我們不確定它存不存在,存在的話就執行它
const fn = null
// do something
const res = fn && fn()
// 可選鏈
const fn = null
// do something
const res = fn?.()
再說說
??
,中文名為空位合併運算子
請看以下程式碼,我們們使用||
運算子,只要左邊是假值
,就會返回右邊的資料const a = 0 || '林三心' // 林三心 const b = '' || '林三心' // 林三心 const c = false || '林三心' // 林三心 const d = undefined || '林三心' // 林三心 const e = null || '林三心' // 林三心
而
??
和||
最大的區別是,在??
這,只有undefined和null
才算假值const a = 0 ?? '林三心' // 0 const b = '' ?? '林三心' // '' const c = false ?? '林三心' // false const d = undefined ?? '林三心' // 林三心 const e = null ?? '林三心' // 林三心
ES12
35、Promise.any
E12新增的Promise的方法
- 接收一個Promise陣列,陣列中如有非Promise項,則此項當做成功
- 如果有一個Promise成功,則返回這個成功結果
如果所有Promise都失敗,則報錯
// 當有成功的時候,返回最快那個成功 function fn(time, isResolve) { return new Promise((resolve, reject) => { setTimeout(() => { isResolve ? resolve(`${time}毫秒後我成功啦!!!`) : reject(`${time}毫秒後我失敗啦!!!`) }, time) }) } Promise.any([fn(2000, true), fn(3000), fn(1000, true)]).then(res => { console.log(res) // 1秒後 輸出 1000毫秒後我成功啦 }, err => { console.log(err) }) // 當全都失敗時 function fn(time, isResolve) { return new Promise((resolve, reject) => { setTimeout(() => { isResolve ? resolve(`${time}毫秒後我成功啦!!!`) : reject(`${time}毫秒後我失敗啦!!!`) }, time) }) } Promise.any([fn(2000), fn(3000), fn(1000)]).then(res => { console.log(res) }, err => { console.log(err) // 3秒後 報錯 all Error })
36、數字分隔符
數字分隔符可以讓你在定義長數字時,更加地一目瞭然
const num = 1000000000 // 使用數字分隔符 const num = 1_000_000_000
37、||= 和 &&=
或等於(||=) a ||= b 等同於 a || (a = b); 且等於(&&=) a &&= b 等同於 a && (a = b);
不知道是ES幾
38、物件計算屬性
我們經常碰到這樣的問題,無論是在微信小程式還是React中,我們需要根據某個條件去修改某個資料
if (type === 'boy') {
this.setData({
boyName: name
})
} else if (type === 'girl') {
this.setData({
girlName: name
})
}
我也不知道這個新特性叫啥,我就自己取名叫屬性動態屬性
哈哈哈
this.setData({
[`${type}Name`]: name
})
補充
39、Symbol
應用場景1:使用Symbol來作為物件屬性名
平常我們物件的屬性都是字串
const obj = {
name: 'Sunshine_Lin',
age: 23
}
console.log(obj['name']) // 'Sunshine_Lin'
console.log(obj['age']) // 23
其實也可以用Symbol來當做屬性名
const gender = Symbol('gender')
const obj = {
name: 'Sunshine_Lin',
age: 23,
[gender]: '男'
}
console.log(obj['name']) // 'Sunshine_Lin'
console.log(obj['age']) // 23
console.log(obj[gender]) // 男
但是Symbol作為屬性的屬性不會被列舉出來,這也是JSON.stringfy(obj)
時,Symbol屬性會被排除在外的原因
console.log(Object.keys(obj)) // [ 'name', 'age' ]
for(const key in obj) {
console.log(key) // name age
}
console.log(JSON.stringify(obj)) // {"name":"Sunshine_Lin","age":23}
其實想獲取Symbol屬性也不是沒辦法。
// 方法一
console.log(Object.getOwnPropertySymbols(obj)) // [ Symbol(gender) ]
// 方法二
console.log(Reflect.ownKeys(obj)) // [ 'name', 'age', Symbol(gender) ]
應用場景2:使用Symbol來替代常量
有以下場景
// 賦值
const one = 'oneXin'
const two = 'twoXin'
function fun(key) {
switch (key) {
case one:
return 'one'
break;
case two:
return 'two'
break;
}
}
如果變數少的話還好,但是變數多的時候,賦值命名很煩,可以利用Symbol的唯一性
const one = Symbol()
const two = Symbol()
應用場景3:使用Symbol定義類的私有屬性
以下例子,PASSWORD屬性無法在例項裡獲取到
class Login {
constructor(username, password) {
const PASSWORD = Symbol()
this.username = username
this[PASSWORD] = password
}
checkPassword(pwd) { return this[PASSWORD] === pwd }
}
const login = new Login('123456', 'hahah')
console.log(login.PASSWORD) // 報錯
console.log(login[PASSWORD]) // 報錯
console.log(login[PASSWORD]) // 報錯
結語
我是林三心,一個熱心的前端菜鳥程式設計師。如果你上進,喜歡前端,想學習前端,那我們們可以交朋友,一起摸魚哈哈,摸魚群,加我請備註【思否】