您好,登錄后才能下訂單哦!
這篇文章主要講解了“ES6實用方法有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“ES6實用方法有哪些”吧!
Array.prototype.includes
判斷一個數組是否包含某個元素,之前一般是這么做的:
if (arr.indexOf(el) >= 0) {} // 或者 if (~arr.indexOf(el)) {}
而現在你可以這么做了:
if (arr.includes(el)) {}
indexOf 會返回找到元素在數組中的索引位置,判斷的邏輯是是否嚴格相等,所以他在遇到 NaN 的時候不能正確返回索引,但是 includes 解決了這個問題:
[1, NaN, 3].indexOf(NaN) // -1 [1, NaN, 3].includes(NaN) // true
求冪運算符(**)
x ** y 是求 x 的 y 次冪,和 Math.pow(x, y) 功能一致:
// x ** y let squared = 2 ** 2 // 2 * 2 = 4 let cubed = 2 ** 3 // 2 * 2 * 2 = 8
x **= y 表示求 x 的 y 次冪,并且把結果賦值給 x:
// x **= y let x = 2; x **= 3 // x 最后等于 8
ES2017
Object.values()
返回一個由對象自身所有可遍歷屬性的屬性值組成的數組:
const person = { name: '布蘭' }; Object.defineProperty(person, 'age', { value: 12, enumrable: false // age 屬性將不可遍歷 }) console.log(Object.values(person)) // ['布蘭'] // 類似 str.split('') 效果 console.log(Object.values('abc')) // ['a', 'b', 'c']
Object.entries()
返回一個由對象自身所有可遍歷屬性的鍵值對組成的數組:
const person = { name: '布蘭', age: 12 } console.log(Object.entries(person)) // [["name", "布蘭"], ["age", 12]]
利用這個方法可以很好的將對象轉成正在的 Map 結構:
const person = { name: '布蘭', age: 12 } const map = new Map(Object.entries(person)) console.log(map) // Map { name: '布蘭', age: 12 }
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptor() 會返回指定對象某個自身屬性的的描述對象,而 Object.getOwnPropertyDescriptors() 則是返回指定對象自身所有屬性的描述對象:
const person = { name: '布蘭', age: 12 } console.log(Object.getOwnPropertyDescriptor(person, 'name')) // { configurable: true, enumerable: true, value: "布蘭", writable: true } console.log(Object.getOwnPropertyDescriptors(person)) //{ // name: { configurable: true, enumerable: true, value: "布蘭", writable: true }, // age: {configurable: false, enumerable: false, value: 12, writable: false} //}
配合 Object.create() 可以實現淺克隆:
const shallowClone = (obj) => Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) )
String.prototype.padStart()
str.padStart(length [, padStr]) 會返回一個新字符串,該字符串將從 str 字符串的左側開始填充某個字符串 padStr(非必填,如果不是字符串則會轉成字符串, 傳入 undefined 和不傳這個參數效果一致)直到達到指定位數 length 為止:
'abc'.padStart(5, 2) // '22abc' 'abc'.padStart(5, undefined) // ' abc' 'abc'.padStart(5, {}) // '[oabc' 'abc'.padStart(5) // ' abc' 'abcde'.padStart(2, 'f') // 'abcde'
String.prototype.padEnd()
規則和 padStart 類似,但是是從字符串右側開始填充:
'abc'.padEnd(5, 2) // 'abc22'
函數參數尾逗號
允許函數在定義和調用的時候時候最后一個參數后加上逗號:
function init( param1, param2, ) { } init('a', 'b',)
Async函數
使用 async 可以聲明一個 async 函數,結合 await 可以用一種很簡介的方法寫成基于 Promise 的異步行為,而不需要刻意的鏈式調用。await 表達式會暫停整個 async 函數的執行進程并出讓其控制權,只有當其等待的基于 Promise 的異步操作被兌現或被拒絕之后才會恢復進程。async 函數有如下幾種定義形式:
// 函數聲明 async function foo() {} // 函數表達式 let foo = async function() {} // 箭頭函數 let foo = async () => {} // 對象方法 lef obj = { async foo() {} } // 類方法 class Dog { async bark() {} }
async 函數一定會返回一個 Promise 對象,所以它可以使用 then 添加處理函數。如果一個 async 函數的返回值看起來不是Promise,那么它將會被隱式地包裝在一個 Promise 中:
async function foo() { return 'a' } foo().then(res => { console.log(res) // 'a' })
內部如果發生錯誤,或者顯示拋出錯誤,那么 async 函數會返回一個 rejected 狀態的 Promsie:
async function foo() { throw new Error('error') } foo().catch(err => { console.log(err) // Error: error })
返回的 Promise 對象必須等到內部所有 await 命令 Promise 對象執行完才會發生狀態改變,除非遇到 return 語句或拋出錯誤;任何一個 await 命令返回的 Promise 對象變 為rejected 狀態,整個 Async 函數都會中斷后續執行:
async function fn() { let a = await Promise.resolve('success') console.log('a_' + a) let b = await Promise.reject('fail') console.log('b_' + b) // 不會執行 } fn().then(res => { console.log(res) // 不會執行 }, err => { console.log(err) }) // 'a_success' // 'fail'
所以為了保證 async 里的異步操作都能完成,我們需要將他們放到 try...catch() 塊里或者在 await 返回的 Promise 后跟一個 catch 處理函數:
async function fn() { try { let a = await Promise.reject('a fail') console.log('a_' + a) // 不會執行 } catch (e) { console.log(e) // 'a fail' } let b = await Promise.reject('b fail') .catch(e => { console.log(e) // 'b fail' }) console.log('b_' + b) // 'bundefined' } fn().then(res => { console.log(res) // undefined }, err => { console.log(err) // 不會執行 })
如果 async 函數里的多個異步操作之間沒有依賴關系,建議將他們寫到一起減少執行時間:
// 寫法一 let [foo, bar] = await Promise.all([getFoo(), getBar()]) // 寫法二 let fooPromise = getFoo() let barPromise = getBar() let foo = await fooPromise let bar = await barPromise
await 命令只能用在 async 函數之中,如果用在普通函數,就會報錯。
共享內存和Atomics對象
SharedArrayBuffer
Atomics
ES2018
Promise.prototype.finally()
Promise.prototype.finally() 用于給 Promise 對象添加 onFinally 函數,這個函數主要是做一些清理的工作,只有狀態變化的時候才會執行該 onFinally 函數。
function onFinally() { console.log(888) // 并不會執行 } new Promise((resolve, reject) => { }).finally(onFinally)
finally() 會生成一個 Promise 新實例,finally 一般會原樣后傳父 Promise,無論父級實例是什么狀態:
let p1 = new Promise(() => {}) let p2 = p1.finally(() => {}) setTimeout(console.log, 0, p2) // Promise {<pending>} let p3 = new Promise((resolve, reject) => { resolve(3) }) let p4 = p3.finally(() => {}) setTimeout(console.log, 0, p3) // Promise {<fulfilled>: 3}
上面說的是一般,但是也有特殊情況,比如 finally 里返回了一個非 fulfilled 的 Promise 或者拋出了異常的時候,則會返回對應狀態的新實例:
let p1 = new Promise((resolve, reject) => { resolve(3) }) let p2 = p1.finally(() => new Promise(() => {})) setTimeout(console.log, 0, p2) // Promise {<pending>} let p3 = p1.finally(() => Promise.reject(6)) setTimeout(console.log, 0, p3) // Promise {<rejected>: 6} let p4 = p1.finally(() => { throw new Error('error') }) setTimeout(console.log, 0, p4) // Promise {<rejected>: Error: error}
參考:
深入理解Promise
異步迭代器
想要了解異步迭代器最好的方式就是和同步迭代器進行對比。我們知道可迭代數據的內部都是有一個 Symbol.iterator 屬性,它是一個函數,執行后會返回一個迭代器對象,這個迭代器對象有一個 next() 方法可以對數據進行迭代,next() 執行后會返回一個對象,包含了當前迭代值 value 和 標識是否完成迭代的 done 屬性:
let iterator = [1, 2][Symbol.iterator]() iterator.next() // { value: 1, done: false } iterator.next() // { value: 2, done: false } iterator.next() // { value: undefinde, done: true }
上面這里的 next() 執行的是同步操作,所以這個是同步迭代器,但是如果 next() 里需要執行異步操作,那就需要異步迭代了,可異步迭代數據的內部有一個 Symbol.asyncIterator屬性,基于此我們來實現一個異步迭代器:
class Emitter { constructor(iterable) { this.data = iterable } [Symbol.asyncIterator]() { let length = this.data.length, index = 0; return { next:() => { const done = index >= length const value = !done ? this.data[index++] : undefined return new Promise((resolve, reject) => { resolve({value, done}) }) } } } }
異步迭代器的 next() 會進行異步的操作,通常是返回一個 Promise,所以需要對應的處理函數去處理結果:
let emitter = new Emitter([1, 2, 3]) let asyncIterator = emitter[Symbol.asyncIterator]() asyncIterator.next().then(res => { console.log(res) // { value: 1, done: false } }) asyncIterator.next().then(res => { console.log(res) // { value: 2, done: false } }) asyncIterator.next().then(res => { console.log(res) // { value: 3, done: false } })
另外也可以使用 for await...of 來迭代異步可迭代數據:
let asyncIterable = new Emitter([1, 2, 3]) async function asyncCount() { for await (const x of asyncIterable ) { console.log(x) } } asyncCount() // 1 2 3
另外還可以通過異步生成器來創建異步迭代器:
class Emitter { constructor(iterable) { this.data = iterable } async *[Symbol.asyncIterator]() { let length = this.data.length, index = 0; while (index < length) { yield this.data[index++] } } } async function asyncCount() { let emitter = new Emitter([1, 2, 3]) const asyncIterable = emitter[Symbol.asyncIterator]() for await (const x of asyncIterable ) { console.log(x) } } asyncCount() // 1 2 3
參考:
Iteration_protocols
for-await...of
s修飾符(dotAll模式)
正則表達式新增了一個 s 修飾符,使得 . 可以匹配任意單個字符:
/foo.bar/.test('foo\nbar') // false /foo.bar/s.test('foo\nbar') // true
上面這又被稱為 dotAll 模式,表示點(dot)代表一切字符。所以,正則表達式還引入了一個dotAll屬性,返回一個布爾值,表示該正則表達式是否處在dotAll模式:
/foo.bar/s.dotAll // true
具名組匹配
正則表達式可以使用捕獲組來匹配字符串,但是想要獲取某個組的結果只能通過對應的索引來獲取:
let re = /(\d{4})-(\d{2})-(\d{2})/ let result = re.exec('2015-01-02') // result[0] === '2015-01-02' // result[1] === '2015' // result[2] === '01' // result[3] === '02'
而現在我們可以通過給捕獲組 (?
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ let result = re.exec('2015-01-02') // result.groups.year === '2015' // result.groups.month === '01' // result.groups.day === '02'
配合解構賦值可以寫出非常精簡的代碼:
let {groups: {year, month, day}} = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.exec('2015-01-02') console.log(year, month, day) // 2015 01 02
具名組也可以通過傳遞給 String.prototype.replace 的替換值中進行引用。如果該值為字符串,則可以使用 $
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ let result = '2015-01-02'.replace(re, '$<day>/$<month>/$<year>') // result === '02/01/2015'
參考:
proposal-regexp-named-groups
后行斷言
后行斷言: (?<=y)x,x 只有在 y 后面才能匹配:
/(?<=\$)\d+/.exec('I have $100.') // ['100']
后行否定斷言: (?<=y)x,x 只有在 y 后面才能匹配:
/(?<!\$)\d+/.exec('I have $100.') // ['00']
Unicode屬性轉義
允許正則表達式匹配符合 Unicode 某種屬性的所有字符,\p{...} 是匹配包含,\P{...}是匹配不包含的字符,且必須搭配 /u 修飾符才會生效:
/\p{Emoji}+/u.exec('??笑死我了??不行了') // ['??'] /\P{Emoji}+/u.exec('??笑死我了??不行了') // ['笑死我了']
這里可以查詢到更多的 Unicode 的屬性 Full_Properties
對象擴展運算符
對象的擴展運算符可以用到解構賦值上,且只能應用到最后一個變量上:
let {x, ...y} = {x: 1, a: 2, b: 3} console.log(y) // {a: 2, b: 3}
對象擴展運算符不能解構原型上的屬性:
let obj = { x: 1 } obj.__proto__ = { y: 2 } let {...a} = obj console.log(a.y) // undefined
應用一:可以實現淺拷貝,但是不會拷貝原始屬性:
let person = Object.create({ name: '布蘭' }) person.age = 12 // 淺拷貝寫法一 let { ...pClone1 } = person console.log(pClone1) // { age: 12 } console.log(pClone1.name) // undefined // 淺拷貝寫法二 let pClone2 = {...person} console.log(pClone2) // { age: 12 } console.log(pClone2.name) // undefined
應用二:合并兩個對象:
let ab = {...a, ...b} // 等同于 let ab = Object.assign({}, a, b);
應用三:重寫對象屬性
let aWithOverrides = { ...a, x: 1, y: 2 };
應用四:給新對象設置默認值
let aWithDefaults = { x: 1, y: 2, ...a };
應用五:利用擴展運算符的解構賦值可以擴展函數參數:
function baseFunction({ a, b }) {} function wrapperFunction({ x, y, ...restConfig }) { // 使用 x 和 y 參數進行操作 // 其余參數傳給原始函數 return baseFunction(restConfig) }
參考:
Object Spread Initializer
Object Rest Destructuring
放松對標簽模板里字符串轉義的限制
參考:
ECMAScript 6 入門
ES2019
允許省略catch里的參數
異常被捕獲的時候如果不需要做操作,甚至可以省略 catch(err) 里的參數和圓括號:
try { } catch { }
JSON.stringify()變動
UTF-8 標準規定,0xD800 到 0xDFFF 之間的碼點,不能單獨使用,必須配對使用。 所以 JSON.stringify() 對單個碼點進行操作,如果碼點符合 UTF-8 標準,則會返回對應的字符,否則會返回對應的碼點:
JSON.stringify('\u{1f600}') // ""?"" JSON.stringify('\u{D834}') // ""\ud834""
Symbol.prototype.description
Symbol 實例新增了一個描述屬性 description:
let symbol = Symbol('foo') symbol.description // 'foo'
Function.prototype.toString()
函數的 toString() 會原樣輸出函數定義時候的樣子,不會省略注釋和空格。
Object.fromEntries()
Object.fromEntries() 方法是 Object.entries() 的逆操作,用于將一個鍵值對數組轉為對象:
let person = { name: '布蘭', age: 12 } let keyValueArr = Object.entries(person) // [['name', '布蘭'], ['age', 12]] let obj = Object.fromEntries(arr) // { name: '布蘭', age: 12 }
常用可迭代數據結構之間的裝換:
let person = { name: '布蘭', age: 12 } // 對象 -> 鍵值對數組 let keyValueArr = Object.entries(person) // [['name', '布蘭'], ['age', 12]] // 鍵值對數組 -> Map let map = new Map(keyValueArr) // Map {"name": "布蘭", "age": 12} // Map -> 鍵值對數組 let arr = Array.from(map) // [['name', '布蘭'], ['age', 12]] // 鍵值對數組 -> 對象 let obj = Array.from(arr).reduce((acc, [ key, val ]) => Object.assign(acc, { [key]: val }), {}) // { name: '布蘭', age: 12 }
參考:
Object.fromEntries
字符串可直接輸入行分隔符和段分隔符
JavaScript 規定有 5 個字符,不能在字符串里面直接使用,只能使用轉義形式。
U+005C:反斜杠(reverse solidus)
U+000D:回車(carriage return)
U+2028:行分隔符(line separator)
U+2029:段分隔符(paragraph separator)
U+000A:換行符(line feed)
但是由于 JSON 允許字符串里可以使用 U+2028 和 U+2029,所以使得 JSON.parse() 去解析字符串的時候可能會報錯,所以 ES2019 允許模板字符串里可以直接這兩個字符:
JSON.parse('"\u2028"') // "" JSON.parse('"\u2029"') // "" JSON.parse('"\u005C"') // SyntaxError
String.prototype.trimStart
消除字符串頭部空格,返回一個新字符串;瀏覽器還額外增加了它的別名函數 trimLeft():
let str = ' hello world ' let newStr = str.trimStart() console.log(newStr, newStr === str) // 'hello world ' false
String.prototype.trimEnd
消除字符串尾部空格,返回一個新字符串;瀏覽器還額外增加了它的別名函數 trimRight():
let str = ' hello world ' let newStr = str.trimEnd() console.log(newStr, newStr === str) // ' hello world' false
Array.prototype.flat()
arr.flat(depth) 按照 depth (不傳值的話默認是 1)深度拍平一個數組,并且將結果以新數組形式返回:
// depth 默認是 1 const arr1 = [1, 2, [3, 4]] console.log(arr1.flat()) // [1, 2, 3, 4] // 使用 Infinity,可展開任意深度的嵌套數組;自動跳過空數組; const arr2 = [1, , [2, [3, [4]]]] console.log(arr2.flat(Infinity)) // [1, 2, 3, 4]
用 reduce 實現拍平一層數組:
const arr = [1, 2, [3, 4]] // 方法一 let newStr = arr.reduce((acc, cur) => acc.concat(cur), []) // 方法二 const flattened = arr => [].concat(...arr) flattened(arr)
參考:
flat
Array.prototype.flatMap()
flatMap(callback) 使用映射函數 callback 映射每個元素,callback 每次的返回值組成一個數組,并且將這個數組執行類似 arr.flat(1) 的操作進行拍平一層后最后返回結果:
const arr1 = [1, 2, 3, 4] arr1.flatMap(x => [x * 2]) // 將 [[2], [4], [6], [8]] 數組拍平一層得到最終結果:[2, 4, 6, 8]
參考:
flatMap
ES2020
String.prototype.matchAll()
String.prototype.matchAll() 方法,可以一次性取出所有匹配。不過,它返回的是一個 RegExpStringIterator 迭代器同是也是一個可迭代的數據結構,所以可以通過 for...of 進行迭代:
let str = 'test1test2' let regexp = /t(e)(st(\d?))/g let iterable = str.matchAll(regexp) for (const x of iterable) { console.log(x) } // ['test1', 'e', 'st1', '1', index: 0, input: 'test1test1', groups: undefined] // ['test2', 'e', 'st2', '2', index: 5, input: 'test1test2', groups: undefined]
?注意當使用 matchAll(regexp) 的時候,正則表達式必須加上 /g 修飾符。?
也可以將這個可迭代數據轉成數組形式:
// 方法一 [...str.matchAll(regexp)] // 方法二 Array.from(str.matchAll(regexp))
動態import()
標準用法的 import 導入的模塊是靜態的,會使所有被導入的模塊,在加載時就被編譯(無法做到按需編譯,降低首頁加載速度)。有些場景中,你可能希望根據條件導入模塊或者按需導入模塊,這時你可以使用動態導入代替靜態導入。
比如按需加載一個模塊可以這樣:
if (xxx) { import('./module.js') }
import() 是異步導入的,結果會返回一個 Promise:
import('/module.js') .then((module) => { // Do something with the module. })
動態 import() 的應用場景挺多的,比如 Vue 中的路由懶加載就是使用的動態導入組件。另外由于動態性不便于靜態分析工具和 tree-shaking 工作,所以不能濫用。
BigInt
BigInt 是一種內置對象,它提供了一種方法來表示大于 - 1 的整數。這原本是 Javascript 中可以用 Number 表示的最大數字。BigInt 可以表示任意大的整數。
為了區分 Number,定義一個 BigInt 需要在整數后面加上一個 n,或者用函數直接定義:
const num1 = 10n const num2 = BigInt(20)
Number 和 BigInt 之間能進行比較,但他們之間是寬松相等;且由于他們表示的是不同類型的數字,所以不能直接進行四則運算:
10n == 10 // true 10n === 10 // false 10n > 8 // true 10 + Number(10n) // 20 10 + 10n // TypeError
Promise.allSettled
Promise.allSettled(iterable) 當所有的實例都已經 settled,即狀態變化過了,那么將返回一個新實例,該新實例的內部值是由所有實例的值和狀態組合成的數組,數組的每項是由每個實例的狀態和內部值組成的對象。
function init(){ return 3 } let p1 = Promise.allSettled([ new Promise((resolve, reject) => { resolve(9) }).then(res => {}), new Promise((resolve, reject) => { reject(6) }), init() ]) let p2 = p1.then(res => { console.log(res) }, err => { console.log(err) }) // [ // {status: "fulfilled", value: undefined}, // {status: "rejected", reason: 6}, // {status: "fulfilled", value: 3} // ]
只要所有實例中包含一個 pending 狀態的實例,那么 Promise.allSettled() 的結果為返回一個這樣 Promise {
globalThis
在以前,從不同的 JavaScript 環境中獲取全局對象需要不同的語句。在 Web 中,可以通過 window、self 或者 frames 取到全局對象,但是在 Web Workers 中,只有 self 可以。在 Node.js 中,它們都無法獲取,必須使用 global。
而現在只需要使用 globalThis 即可獲取到頂層對象,而不用擔心環境問題。
// 在瀏覽器中 globalThis === window // true
import.meta
import.meta 是一個給 JavaScript 模塊暴露特定上下文的元數據屬性的對象。它包含了這個模塊的信息,比如說這個模塊的 URL,import.meta 必須在一個模塊里使用:
// 沒有聲明 type="module",就使用 import.meta 會報錯 <script type="module" src="./js/module.js"></script> // 在module.js里 console.log(import.meta) // {url: "http://localhost/3ag/js/module.js"}
如果需要在配置了 Webpack 的項目,比如 Vue 里使用 import.meta 需要加一個包且配置一下參數,否則項目編譯階段會報錯。
包配置詳情參考:
@open-wc/webpack-import-meta-loader
比如我用的是 4.x 版本的 vue-cli,那我需要在 vue.config.js 里配置:
module.exports = { chainWebpack: config => { config.module .rule('js') .test(/\.js$/) .use('@open-wc/webpack-import-meta-loader') .loader('@open-wc/webpack-import-meta-loader') .end() } }
可選鏈操作符(?.)
通常我們獲取一個深層對象的屬性會需要寫很多判斷或者使用邏輯與 && 操作符,因為對象的某個屬性如果為 null 或者 undefined 就有可能報錯:
let obj = { first: { second: '布蘭' } } // 寫法一 let name1 = '' if (obj) { if (obj.first) { name1 = obj.first.second } } // 寫法二 let name2 = obj && obj.first && obj.first.second
?. 操作符允許讀取位于連接對象鏈深處的屬性的值,而不必明確驗證鏈中的每個引用是否有效。如果某個屬性為 null 或者 undefined 則結果直接為 undefined。有了可選鏈操作符就可以使得表達式更加簡明了,對于上面例子用可選鏈操作符可以這么寫:
let name3 = obj?.first?.second
空值合并操作符(??)
對于邏輯或 || 運算符,當對運算符左側的操作數進行裝換為 Boolean 值的時候,如果為 true,則取左邊的操作數為結果,否則取右邊的操作數為結果:
let name = '' || '布蘭' console.log(name) // '布蘭'
我們都知道 ''、0、null、undefined、false、NaN 等轉成 Boolean 值的時候都是 false,所以都會取右邊的操作數。這個時候如果要給變量設置默認值,如果遇到本身值就可能是 '' 或 0 的情況那就會出錯了,會被錯誤的設置為默認值了。
而 ?? 操作符就是為了解決這個問題而出現的,x ?? y 只有左側的操作數為 null 或 undefined 的時候才取右側操作數,否則取左側操作數:
let num = 0 ?? 1 console.log(num) // 0
ES2021
如下這幾個提案已經確定了會在 2021 年發布,所以把他們歸到 ES2021 中。
String.prototype.replaceAll
之前需要替換一個字符串里的全部匹配字符可以這樣做:
const queryString = 'q=query+string+parameters' // 方法一 const withSpaces1 = queryString.replace(/\+/g, ' ') // 方法二 const withSpaces2 = queryString.split('+').join(' ')
而現在只需要這么做:
const withSpace3 = queryString.replaceAll('+', ' ')
?replaceAll 的第一個參數可以是字符串也可以是正則表達式,當是正則表達式的時候,必須加上全局修飾符 /g,否則報錯。?
參考:
string-replaceall
Promise.any()
Promsie.any() 和 Promise.all() 一樣接受一個可迭代的對象,然后依據不同的入參會返回不同的新實例:
傳一個空的可迭代對象或者可迭代對象所有 Promise 都是 rejected 狀態的,則會拋出一個 AggregateError 類型的錯誤,同時返回一個 rejected 狀態的新實例:
let p1 = Promise.any([]) let p2.catch(err => {}) setTimeout(console.log, 0, p1) // Promise {<rejected>: AggregateError: All promises were rejected}
只要可迭代對象里包含任何一個 fulfilled 狀態的 Promise,則會返回第一個 fulfilled 的實例,并且以它的值作為新實例的值:
let p = Promise.any([ 1, Promise.reject(2), new Promise((resolve, reject) => {}), Promise.resolve(3), ]) setTimeout(console.log, 0, p) // Promise {<fulfilled>: 1}
其他情況下,都會返回一個 pending 狀態的實例:
let p = Promise.any([ Promise.reject(2), Promise.reject(3), new Promise((resolve, reject) => {}), ]) setTimeout(console.log, 0, p) // Promise {<pending>: undefined}
WeakRef
我們知道一個普通的引用(默認是強引用)會將與之對應的對象保存在內存中。只有當該對象沒有任何的強引用時,JavaScript 引擎 GC 才會銷毀該對象并且回收該對象所占的內存空間。
WeakRef 對象允許你保留對另一個對象的弱引用,而不會阻止被弱引用的對象被 GC 回收。WeakRef 的實例方法 deref() 可以返回當前實例的 WeakRef 對象所綁定的 target 對象,如果該 target 對象已被 GC 回收則返回 undefined:
let person = { name: '布蘭', age: 12 } let wr = new WeakRef(person) console.log(wr.deref()) // { name: '布蘭', age: 12 }
?正確使用 WeakRef 對象需要仔細的考慮,最好盡量避免使用。這里面有諸多原因,比如:GC 在一個 JavaScript 引擎中的行為有可能在另一個 JavaScript 引擎中的行為大相徑庭,或者甚至在同一類引擎,不同版本中 GC 的行為都有可能有較大的差距。GC 目前還是 JavaScript 引擎實現者不斷改進和改進解決方案的一個難題。?
參考:
WeakRef
內存管理
邏輯賦值符
邏輯賦值符包含 3 個:
x &&= y:邏輯與賦值符,相當于 x && (x = y)
x ||= y:邏輯或賦值符,相當于 x || (x = y)
x ??= y:邏輯空賦值符,相當于 x ?? (x = y)
看如下示例,加深理解:
let x = 0 x &&= 1 // x: 0 x ||= 1 // x: 1 x ??= 2 // x: 1 let y = 1 y &&= 0 // y: 0 y ||= null // y: null y ??= 2 // y: 2
數值分隔符(_)
對于下面一串數字,你一眼看上去不確定它到底是多少吧?
const num = 1000000000
那現在呢?是不是可以很清楚的看出來它是 10 億:
const num = 1_000_000_000
數值分隔符(_)的作用就是為了讓數值的可讀性更強。除了能用于十進制,還可以用于二級制,十六進制甚至是 BigInt 類型:
let binarary = 0b1010_0001_1000_0101 let hex = 0xA0_B0_C0 let budget = 1_000_000_000_000n
使用時必須注意 _ 的兩邊必須要有類型的數值,否則會報錯,以下這些都是無效的寫法:
let num = 10_ let binarary = 0b1011_ let hex = 0x_0A0B let budget = 1_n
感謝各位的閱讀,以上就是“ES6實用方法有哪些”的內容了,經過本文的學習后,相信大家對ES6實用方法有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。