关于javascript:ES11屡试不爽的新特性你用上了几个

6次阅读

共计 7169 个字符,预计需要花费 18 分钟才能阅读完成。

ES11 标准于往年的年初实现,引入了许多新规范,本文讲着重钻研下其中几个实用且乏味的新规范

个性领先知:

  • 公有变量
  • Promise.allSettled
  • BigInt 全新的数据类型
  • Nullish Coalescing Operator 空位合并运算符
  • Optional Chaining Operator 可选链运算符
  • Dynamic Import 动静导入
  • String.prototype.matchAll 新增 matchAll
  • globalThis 新增全局对象
  • Module Namespace Exports 导入特定命名空间

公有变量

严格限度一些用于外部应用的 Class 变量,只须要在变量前 增加 #,就能够使其成为公有变量,并且无奈在 class 内部间接拜访

上面咱们以一个简略的

class Hero {
    #aggressivity = 0
    constructor (aggressivity){this.#aggressivity = aggressivity}
    getHurt(){return this.#aggressivity}
    setAggressivity(aggressivity){this.#aggressivity = aggressivity}
}

const shooter = new Hero(100)
let hurt = shooter.getHurt()
console.log(hurt) //100
console.log(shooter.#aggressivity) //Error : Uncaught SyntaxError: Private field '#aggressivity' must be declared in an enclosing class

下面代码咱们会发现,无奈间接进行拜访 #aggressivity, 将抛出异样
只能通过 class 里进行拜访,可通过对立 class 的公共办法进行对立批改

假如目前射手携带了 狂暴 技能,晋升了10% 挫伤,咱们能够通过 setAggressivity 来批改攻击力

let aggressivity = parseInt(hurt * 1.1)
shooter.setAggressivity(aggressivity)
console.log(shooter.getHurt()) // 110

Promise.allSettled

谈及这个新个性之前,咱们先简略回顾下 Promise.all 以及 Promise.race, 揣测下为什么须要Promise.allSettled 这个新个性

Promise.all:能够将多个 Promise 实例包装成一个新的 Promise 实例。同时,胜利和失败的返回值是不同的,胜利的时候返回的是一个后果数组,而失败的时候则返回最先被 reject 失败状态的值

let p1 = new Promise((resolve, reject) => {resolve('胜利了')
})

let p2 = new Promise((resolve, reject) => {resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {console.log(result) //['胜利了', 'success']
}).catch((error) => {console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {console.log(result)
}).catch((error) => {console.log(error) // 失败了,打出 '失败'
})

Promise.race: 返回一个 promise,一旦某个 Promise 触发 resolve 或者 reject,就间接返回该 promise 后果状态

const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {console.log(value);
});
// 输入 "two" 因为 promise2 返回后果比 promise1 快

有时候咱们可能须要晓得所有的后果做一些操作,并不关怀其执行后果是否胜利,在没有 Promise.allSettled 之前,咱们须要本人实现,可通过如下 实现 Promise.allSettled

let allSettled = (funcArr) => {return new Promise((resolve) => {
    let sttled = 0
    let result = []
    for(let index = 0;index<funcArr.length;index++){const element = funcArr[index]
      element
      .then(res => {result[index] = {
          status: 'fulfilled',
          value: res
        }
      })
      .catch(err => {result[index] = {
          status: 'rejected',
          reason: err
        }
      })
      .finally(() => { ++sttled === funcArr.length && resolve(result) })
    }
  })
}

// 应用
const promises = [Promise.reject('c'),
    Promise.resolve('a'),
    Promise.resolve('b'),
];

allSettled(promises).then(res => {console.log(res)
})

// 打印后果
// [{"status":"rejected","reason":"c"},
// {"status":"fulfilled","value":"a"},
// {"status":"fulfilled","value":"b"}]

而 Promise.allSettled 新个性进去后,咱们能够间接应用而不须要独自去实现了

const promises = [Promise.reject('c'),
    Promise.resolve('a'),
    Promise.resolve('b'),
];
Promise.allSettled(promises).then(res =>{console.log(res)
})
// 打印后果
// [{"status":"rejected","reason":"c"},
// {"status":"fulfilled","value":"a"},
// {"status":"fulfilled","value":"b"}]

返回后果里会将返回一个数组,蕴含了所有胜利与失败的后果,数组每项为对象,均含有 status 属性,对应 fulfilled 和 rejected。
当状态为 fulfilled 时,代表着胜利,蕴含一个 value,代表着胜利的后果
当状态为 rejected 时,代表着失败,蕴含一个reason,代表着失败的起因

BigInt

JS 中短少显式整数类型经常令人困惑。许多编程语言反对多种数字类型,如浮点型、双精度型、整数型和双精度型,但 JS 却不是这样。在 JS 中,依照 IEEE 754-2008 规范的定义,所有数字都以双精度 64 位浮点格局 示意。

在此规范下,无奈准确示意的十分大的整数将主动四舍五入。确切地说,JS 中的 Number 类型只能平安地示意 -9007199254740991 (-(2^53-1)) 和 9007199254740991(2^53-1)之间的整数,任何超出此范畴的整数值都可能失去精度。

console.log(9999999999999999);    //10000000000000000

JS 提供 Number.MAX_SAFE_INTEGER 常量来示意 最大平安整数,Number.MIN_SAFE_INTEGER常量示意最小平安整数:

// 留神最初一位的数字
const A = Number.MAX_SAFE_INTEGER + 1
const B = Number.MAX_SAFE_INTEGER + 2

console.log(Number.MAX_SAFE_INTEGER) //9007199254740991
console.log(A) //9007199254740992
console.log(B) //9007199254740992

console.log(A === B) //true

当数据超出范围就会失去精度,达不到咱们预期的后果。

BigInt 横空出世,能够在规范 JS 中执行对大整数的算术运算,不用放心精度损失危险

创立 BigInt 数据类型的形式非常简单,在整数前面追加 n 即可,或者 通过 BigInt()进行创立实例

const bigint = 999999999999999999n
const bigintByMethod = BigInt('999999999999999999')
console.log(bigint) //999999999999999999n
console.log(bigintByMethod) //999999999999999999n
console.log(bigint === bigintByMethod) //true

// 布尔值
console.log(BigInt(true)) //1n
console.log(BigInt(false)) //0n

console.log(typeof bigint) //"bigint" 

BigInt 与 Number 是两种数据类型,无奈进行运算,能够进行大小比拟

console.log(88n == 88) //true
console.log(88n === 88) //false
console.log(88n+1) //Error =>Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

BigInt 之间,除了一元加号(+)运算符 外,其余均可用于 BigInt

console.log(1n + 2n) //3n
console.log(1n - 2n) //-1n
console.log(+ 1n) //Uncaught TypeError: Cannot convert a BigInt value to a number
console.log(- 1n) //-1n
console.log(10n * 20n) //200n
console.log(23n%10n) //3n
console.log(20n/10n) //2n
......

须要留神的是,除法运算符会主动向下舍入到最靠近的整数

console.log(25n / 10n) //2n
console.log(29n / 10n) //2n

最初还有个留神点就是,Boolean 类型和 BigInt 类型的转换时,解决形式和 Number 类型,只有 不是 0n,BigInt 就被视为 true

if (5n) {// 这里代码块将被执行}

if (0n) {// 这里代码块不会执行}

Nullish Coalescing Operator 空位合并运算符

新增一个逻辑运算符??,解决 null 和 undefined,工作原理与逻辑 or(||)相似,然而与此相反

|| 如果为真即返回左侧值,否则返回右侧

0 || 5 // return 5
""|| 5 // return 5" 前端公虾米 "||'V5'//return" 前端公虾米 "

?? 如果为 null 或者 undefined,即返回右侧,否则返回左侧

0 ?? 5 //return 0
""?? 5 //return""
null ?? 5 // return 5
undefined ?? 5 // return 5
false ?? 5 //return false
NaN ?? 5 // return NaN

在应用该?? 运算符时,须要留神的是

  • 不可与其余运算符组合应用,例如 &&、||
  • 但若应用括号包裹则能够组合应用
"前端公虾米" || undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??'
"前端公虾米" && undefined ?? "Sneaker" //Uncaught SyntaxError: Unexpected token '??'

("前端公虾米" || undefined) ?? "公 ^ 众 ^ 号" //"前端公虾米"
("回复学习支付视频材料" && null) ?? "一起学习" //"一起学习"

Optional Chaining Operator 可选链运算符

日常开发中,不少开发者会碰到 Cannot read property XXX of undefined,抛出无奈从未定义的数据中读取某个字段

可选链运算符在查找嵌套对象时,找到链中的第一个 undefined 或者 null 后会立刻终止,并返回undefined,而不会一直向下查找而导致抛错

const obj = {
  foo: {
    bar: {baz: 42,},
  },
}
console.log(obj.fo.bar.baz) //Uncaught TypeError: Cannot read property 'bar' of undefined

在诸如此类的对象里,咱们通常进行数据安全检查来拜访嵌套对象,否则将抛错
if(obj&&obj.foo&&obj.foo.bar){console.log(obj.foo.bar.baz) // 42
}

在可选链运算符可应用的当初,咱们只需这样进行属性的读取

console.log(obj?.foo?.bar?.baz) //42
            
console.log(obj.foo.bar?.baz) //42

Dynamic Import 动静导入

在规范的 import 导入中,是动态导入的,所有被导入的模块是在加载时就被编译的,无奈按需编译。当咱们须要条件导入的时候,都只能应用require().

但当初,咱们有方法改善此类情况了,因为动静导入能够无效的缩小未应用代码的编译,能够进步首屏加载速度,按需加载。
那么,为什么咱们须要动静导入呢?

  • 动态导入耗费加载工夫,很多模块并非首屏须要渲染
  • 动态导入会在导入时耗费大量内存
  • 可能会存在有些模块在加载时不存在
  • 缩小一些有条件依赖的副作用
// 通用导入形式
import("/module/sneaker/test.js")
.then(module => {// 模块相干操作})

//await
const getModule = await import("/module/sneaker/test.js")

// 通过 async await
const getUserInfo = async (hasLogin) => {if(!hasLogin){const user = await import("/module/sneaker/user.js")
    user.getInfo()}
}

matchAll

基于 String 原型上的一个新办法,容许咱们匹配一个字符串和一个正则表达式,返回值是所有匹配后果的迭代器。
能够通过 for…of 遍历或者 操作符 …Array.from将后果迭代器转换成数组

const string = 'Hello Sneaker,Where is the library?'
const regex = /[A-W]/g
const matches = string.matchAll(regex)

console.log(...matches)
//["H", index: 0, input: "Hello Sneaker,Where is the library?", groups: undefined] 
//["S", index: 6, input: "Hello Sneaker,Where is the library?", groups: undefined] 
//["W", index: 14, input: "Hello Sneaker,Where is the library?", groups: undefined] 

globalThis

这是为了提供一种拜访全局对象的规范办法。
在浏览器中,咱们能够应用 window/self/frames 来拜访全局对象,但对于 Web Workers 只能应用self,Node 中又齐全不同,须要应用global

globalThis 成为规范之前,获取全局对象咱们可能须要这么做

const globalObj = (()=>{if(self) return self
  if(window) return window
  if(global) return global
  throw new Error('Sorry!No global obj found')
})
//Browser 
globalThis === window //true

//Webworker
globalThis === self //true

//Node
globalThis === global //true

从此实现全局对象的大一统!

Module Namespace Exports 导入特定命名空间

export * as ns from './module

// 等同于
import * as ns from './module'
export {ns}

导入特定命名空间实则并没有导入模块,只是对模块进行转发,导致在此模块中不可间接应用此模块

参考

  • ecma-262
  • MDN

最初

个性很多但有的很乏味,比方可选链和空位合并运算符,屡试不爽,至于有多爽,你试了才晓得。新个性平时不写还是容易疏忽淡忘的,倡议平时能够下意识的常常回顾使用,一起学习一起成长。

本文首发公众号【前端公虾米】,如有谬误,还望分割我指出【y3517320520】

正文完
 0