#### 五.ES10新特性
##### 1. Object.fromEntries
> Object.fromEntries()方法允許你輕松地將鍵值對列表轉換為對象
```js
const arr = [["name", "kerwin"], ["age", 100]];
console.log(Object.fromEntries(arr))//{name: 'kerwin', age: 100}
const m = new Map()
m.set("name","tiechui")
m.set("age",18)
console.log(Object.fromEntries(m))
```
**用處**
```js
let str ="name=kerwin&age=100"
let searchParams = new URLSearchParams(str)
console.log(Object.fromEntries(searchParams))//{name: 'kerwin', age: '100'}
```
##### 2. trimStart() and trimEnd()
> trimStart()和trimEnd()方法在實現與trimLeft()和trimRight()相同。
```js
let str = " ? kerwin ? ?"
console.log("|"+str.trimStart(str)+"|")
console.log("|"+str.trimEnd(str)+"|")
console.log("|"+str.trimLeft(str)+"|")
console.log("|"+str.trimRight(str)+"|")
```
?
##### 3. Symbol 對象的 description 屬性
> 為Symbol對象添加了只讀屬性 description ,該對象返回包含Symbol描述的字符串。
```js
let s = Symbol("kerwin")
console.log(s.description) //kerwin
```
##### 4. 可選的 catch
```js
let pro1 = new Promise(function (resolve, reject) {
? ? //執行器函數
? ? setTimeout(() => {
? ? ? ? resolve("成功的結果")
? ? }, 30000)
})
let pro2 = new Promise(function (resolve, reject) {
? ? //執行器函數
? ? setTimeout(() => {
? ? ? ? reject()
? ? }, 2000)
})
async function test() {
? ? try {
? ? ? ? await Promise.race([pro1, pro2])
? ? } catch {
? ? ? ? console.log("不關心錯誤結果,網絡超時")
? ? }
}
test()
```
?
#### 六. ES11新特性
##### 1. Promise.allSettled
> Promise.allSettled() 方法返回一個在所有給定的 promise 都已經 fulfilled 或 rejected 后的 promise ,并帶有一個對象數組,每個對象表示對應的 promise 結果。
```js
const promises = [ ajax('/200接口'), ajax('/401接口') ];
Promise.allSettled(promises).then(results=>{
? ? // 過濾出成功的請求
? ? results.filter(item =>item.status === 'fulfilled');
? ? 過濾出失敗的請求
? ? results.filter(item=> item.status === 'rejected');
})
```
?
##### 2.module新增
###### 2-1 動態導入 import()
> 標準用法的 import 導入的模塊是靜態的,會使所有被導入的模塊,在加載時就被編譯(無法做到按需編譯,降低首頁加載速度)。有些場景中,你可能希望根據條件導入模塊或者按需導入模塊,這時你可以使用動態導入代替靜態導入。
```js
<body>
? ? <button>login</button>
? ? <script type="module">
? ? ? ? let role1 = "管理員"
? ? ? ? let role2 = "普通用戶"
? ? ? ? function login(){
? ? ? ? ? ? return "普通用戶"
? ? ? ? }
? ? ? ? async function render(role){
? ? ? ? ? ? if(role===role1){
? ? ? ? ? ? ? ? let res1 = await import("./1.js")
? ? ? ? ? ? ? ? console.log(res1.default)
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? let res2 = await import("./2.js")
? ? ? ? ? ? ? ? console.log(res2.default)
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? let obtn = document.querySelector("button")
? ? ? ? obtn.onclick = function(){
? ? ? ? ? ? let role = login()
? ? ? ? ? ? render(role)
? ? ? ? }
? ? </script>
</body>
```
?
###### 2-2 import.meta
import.meta 會返回一個對象,有一個 url 屬性,返回當前模塊的url路徑,只能在模塊內部使用。
```js
<script type="module">
? ? ? ? import obj from './1.js'
</script>
?
//1.js
console.log(import.meta)
export default {
? ?
}
```
?
###### 2-3 export * as obj from 'module'
```js
//1.js
export default {
? ? name:'111111'
}
export function test1(){
? ?
}
//2.js
export default {
? ? name:"22222"
}
export function test2(){
? ?
}
export * as obj1 from './1.js'
//html
?<script type="module">
? ? ? ? import * as obj from './2.js'
? ? ? ? console.log(obj)
?</script>
```
?
<img src="%E7%AC%94%E8%AE%B0.assets/image-20220922111416681.png" alt="image-20220922111416681" style="zoom:67%;float:left;" />
?
##### 3.字符串的matchAll方法
> matchAll() 方法返回一個包含所有匹配正則表達式的結果的迭代器。可以使用 for...of 遍歷,或者使用 展開運算符(...) 或者 Array.from 轉換為數組.
```js
let str = `
<ul>
<li>1111</li>
<li>2222</li>
<li>3333</li>
<li>4444</li>
</ul>
`
let reg = /<li>(.*)<\/li>/g
console.log(str.match(reg))
//'<li>1111</li>', '<li>2222</li>', '<li>3333</li>', '<li>4444</li>'
```
```js
let str = `
<ul>
<li>1111</li>
<li>2222</li>
<li>3333</li>
<li>4444</li>
</ul>
`
let reg = /<li>(.*)<\/li>/g
let match = null;
while(match = reg.exec(str)){
? ? console.log(match[0])
? ? console.log(match[1])
}
```
?
```js
let str = `
<ul>
<li>1111</li>
<li>2222</li>
<li>3333</li>
<li>4444</li>
</ul>
`
let reg = /<li>(.*)<\/li>/g
for(let i of str.matchAll(reg)){
? ? console.log(i)
}
```
?
##### 4. BigInt
> JavaScript 能夠準確表示的整數范圍在-2^53到2^53之間(不含兩個端點),超過這個范圍,無法精確表示這個值,這使得 JavaScript 不適合進行科學和金融方面的精確計算。
```js
9007199254740992 //9007199254740992
9007199254740993 //9007199254740992
Math.pow(2,53) === Math.pow(2,53)+1
```
?
為了與 Number 類型區別,BigInt 類型的數據必須添加后綴`n`。
```js
1234 // 普通整數
1234n // BigInt
// BigInt 的運算
1n + 2n // 3n
```
?
##### 5. globalThis
> globalThis 提供了一個標準的方式來獲取不同環境下的全局 this 對象(也就是全局對象自身)。不像 window 或者 self這些屬性,它確保可以在有無窗口的各種環境下正常工作。所以,你可以安心的使用 globalThis,不必擔心它的運行環境。為便于記憶,你只需要記住,全局作用域中的 this 就是 globalThis。
>
```js
//es6-shim
var getGlobal = function () {
// the only reliable means to get the global object is
? ? // Function('return this')()
? ? // However, this causes CSP violations in Chrome apps.
? ? ?if (typeof self !== 'undefined') { return self; }
? ?
? ? ? ? if (typeof window !== 'undefined') { return window; }
? ?
? ? ? ? if (typeof global !== 'undefined') { return global; }
? ?
? ? ? ? throw new Error('unable to locate global object');
};
var globals = getGlobal();
if (!globals.Reflect) {
defineProperty(globals, ‘Reflect’, {}, true);
}
```
?
```js
//以前
var getGlobal = function () {
? ? if (typeof self !== 'undefined') { return self; }
? ? if (typeof window !== 'undefined') { return window; }
? ? if (typeof global !== 'undefined') { return global; }
? ? throw new Error('unable to locate global object');
};
let globals = getGlobal()
if (globals.document) {
? ? console.log("進行dom操作相關")
} else {
? ? console.log("不能進行dom操作")
}
//現在
if (globalThis.document) {
? ? console.log("進行dom操作相關")
} else {
? ? console.log("不能進行dom操作")
}
```
?
##### 6.空值合并運算符
> **空值合并運算符(*??*)**是一個邏輯運算符。當左側操作數為 null 或 undefined 時,其返回右側的操作數。否則返回左側的操作數。
```js
let obj = {
? ? name:"kerwin",
? ? introduction:0
}
console.log(obj.introduction || "這個人很懶")
console.log(obj.introduction ?? "這個人很懶")
```
**??和 || 的區別是什么呢?**
他們兩個最大的區別就是 ’ '和 0,??的左側 為 ’ '或者為 0 的時候,依然會返回左側的值;
|| 會對左側的數據進行boolean類型轉換,所以’ '和 0 會被轉換成false,返回右側的值
?
##### 7.可選鏈操作符
> 可選鏈前面的值如果是null或undefined,則不再執行后面的,之前返回可選鏈前面的值
```js
let obj = {
? ? name:"kerwin",
? ? introduction:0,
? ? // location:{
? ? // ? ? city:"dalian"
? ? // }
}
console.log(obj && obj.location && obj.location.city)
console.log(obj?.location?.city)
```
?
#### 七. ES12新特性
##### 1. 邏輯賦值操作符
邏輯賦值操作符 ??=、&&=、 ||=
```js
let a = true
let b = false
//a &&= b //false
a ||= b ; //true
console.log(a)
?
let obj = {
? ? name:"kerwin", ? ? ? ? ?
}
obj.introduction = obj.introduction??"很懶"
obj.introduction??="很懶"
```
?
##### 2.數字分隔符
這個新特性是為了方便程序員看代碼而出現的,如果數字比較大,那么看起來就不是那么一目了然
```js
const num= 123456789;
```
分隔符不僅可以分割十進制,也可以分割二凈值或者十六凈值的數據,非常好用。
```javascript
const number = 1_000_000_000_000;
const binary = 0b1010_0101_1111_1101;
const hex = 0xA1_B2_C3;
```
?
##### 3. replaceAll
> 所有匹配都會被替代項替換。模式可以是字符串或正則表達式,而替換項可以是字符串或針對每次匹配執行的函數。并返回一個全新的字符串 ?
```js
const str =
? ? ? "I wish to wish the wish you wish to wish, but if you wish the wish the witch wishes, I won't wish the wish you wish to wish. ";
const newStr = str.replaceAll("wish", "kerwin");
console.log(newStr);
```
?
##### 4.Promise.any
只要參數實例有一個變成`fulfilled`狀態,包裝實例就會變成`fulfilled`狀態;如果所有參數實例都變成`rejected`狀態,包裝實例就會變成`rejected`狀態。
> `Promise.any()`跟`Promise.race()`方法很像,只有一點不同,就是`Promise.any()`不會因為某個 Promise 變成`rejected`狀態而結束,必須等到所有參數 Promise 變成`rejected`狀態才會結束。
##### 5. WeakRef
?
> 在一般情況下,對象的引用是強引用的,這意味著只要持有對象的引用,它就不會被垃圾回收。只有當該對象沒有任何的強引用時,垃圾回收才會銷毀該對象并且回收該對象所占的內存空間。
>
> 而 `WeakRef` 允許您保留對另一個對象的弱引用,而不會阻止被弱引用對象被垃圾回收。
```js
let target = {};
let wr = new WeakRef(target);
```
WeakRef 實例對象有一個`deref()`方法,如果原始對象存在,該方法返回原始對象;如果原始對象已經被垃圾回收機制清除,該方法返回`undefined`。
```js
let target = {};
let wr = new WeakRef(target);
let obj = wr.deref();
if (obj) { // target 未被垃圾回收機制清除
? // ...
}
```
?
```js
let like = new WeakRef(document.getElementById("like"))
let mymap = new WeakMap()
mymap.set(like.deref(), {
? ? click: 0
})
like.deref().onclick = function () {
? ? let times = mymap.get(like.deref())
? ? times.click++
}
setTimeout(() => {
? ? document.body.removeChild(like.deref())
}, 2000)
```
?
##### 6. FinalizationRegistry
> 清理器注冊表功能 FinalizationRegistry,用來指定目標對象被垃圾回收機制清除以后,所要執行的回調函數。
首先,新建一個注冊表實例。
```javascript
const registry = new FinalizationRegistry(data => {
? // ....
});
```
```javascript
registry.register(obj, "some value");
registry.unregister(obj);
```
?
```js
let like = new WeakRef(document.getElementById("like"))
let mymap = new WeakMap()
mymap.set(like.deref(), {
? ? click: 0
})
like.deref().onclick = function () {
? ? let times = mymap.get(like.deref())
? ? times.click++
}
setTimeout(() => {
? ? // registry.register(document.getElementById("like"), mymap.get(like.deref()));
? ? registry.register(like.deref(), mymap.get(like.deref()));
? ? document.body.removeChild(like.deref())
}, 2000)
?
const registry = new FinalizationRegistry(data => {
? ? // ....
? ? console.log("被銷毀了", data)
});
```
?
#### 八.ES13新特性
##### 1. 私有屬性和方法
```js
class Cache{
? ? #obj ?={}
? ? get(key){
? ? ? ? return this.#obj[key]
? ? }
set(key,value){
? ? this.#obj[key] =value
}
}
let cache = new Cache()
cache.set("name","kerwin")
```
##### 2.靜態成員的私有屬性和方法
> 我們還可以給類定義靜態成員和靜態私有函數。類的靜態方法可以使用`this`關鍵字訪問其他的私有或者公有靜態成員,
```js
?class Cache{
? ? ?static #count = 0;
? ? ?static getCount(){
? ? ? ? ?return this.#count
? ? ?}
? ? #obj ?={}
? ? get(key){
? ? ? ? return this.#obj[key]
? ? }
? ? set(key,value){
? ? ? ? this.#obj[key] =value
? ? }
}
let cache = new Cache()
cache.set("name","kerwin")
console.log(Cache.getCount())
```
?
##### 3.靜態代碼塊
> ES13允許在類中通過`static`關鍵字定義一系列靜態代碼塊,這些代碼塊只會在類被創造的時候**執行一次**。這其實有點像一些其他的如C#和Java等面向對象的編程語言的靜態構造函數的用法。
?
一個類可以定義任意多的靜態代碼塊,這些代碼塊會和穿插在它們之間的靜態成員變量一起按照定義的順序在類初始化的時候執行一次。我們還可以使用`super`關鍵字來訪問父類的屬性。
```js
?class Cache{
? ? static obj = new Map()
? ? static {
? ? ? ? this.obj.set("name","kerwin")
? ? ? ? this.obj.set("age",100)
? ? }
? ? static{
? ? ? ? console.log(this.obj)
? ? }
}
console.log(Cache.obj)
```
?
##### 4. 使用in來判斷某個對象是否擁有某個私有屬性
```js
class Cache {
? ? #obj = {}
? ? get(key) {
? ? ? ? return this.#obj[key]
? ? }
? ? set(key, value) {
? ? ? ? this.#obj[key] = value
? ? }
? ? hasObj(){
? ? ? ? return #obj in this
? ? }
}
let cache = new Cache()
console.log(cache.hasObj())
```
?
##### 5.支持在最外層寫await
> 頂層`await`只能用在 ES6 模塊,不能用在 CommonJS 模塊。這是因為 CommonJS 模塊的`require()`是同步加載,如果有頂層`await`,就沒法處理加載了。
```js
<script type="module">
? ? function ajax() {
? ? return new Promise((resolve) => {
? ? ? ? setTimeout(() => {
? ? ? ? ? ? resolve("data-1111");
? ? ? ? }, 1000);
? ? })
}
let res = await ajax();
console.log(res)
</script>
```
?
##### 6. at函數來索引元素
```js
let arr = ["kerwin","tiechui","gangdan","xiaoming"]
console.log(arr[1])
console.log(arr[arr.length-1]) //變丑了
console.log(arr[arr.length-2]) //變丑了
console.log(arr.at(1))
console.log(arr.at(-1))
console.log(arr.at(-2))
```
?
##### 7. 正則匹配的開始和結束索引
```js
let str = "今天是2022-11-10"
let reg = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/d
//exec
let res = reg.exec(str)
console.log(res)
```

?
##### 8.findLast()和findLastIndex()函數
```js
let arr = [11,12,13,14,15]
// let res = arr.find(function(value){
// ? return value % 2 === 0
// })
// let res = arr.findIndex(function(value){
// ? return value % 2 === 0
// })
// let res = arr.findLast(function(value){
// ? return value % 2 === 0
// })
let res = arr.findLastIndex(function(value){
? ? return value % 2 === 0
})
console.log(res)
```
##### 9.Error對象的Cause屬性
> Error對象多了一個`cause`屬性來指明錯誤出現的原因。這個屬性可以幫助我們為錯誤添加更多的上下文信息,從而幫助使用者們更好地定位錯誤。
```js
function getData(){
? ? try{
? ? ? ? console.log(kerwin)
? ? }
? ? catch(e){
? ? ? ? throw new Error('New error 1111111',{cause:"這是因為,,,,,,,,,"});
? ? }
}
?
try{
? ? getData()
}catch(e){
? ? console.log(e.cause)
}
```
?