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) //100console.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 + 1const B = Number.MAX_SAFE_INTEGER + 2console.log(Number.MAX_SAFE_INTEGER) //9007199254740991console.log(A) //9007199254740992console.log(B) //9007199254740992console.log(A === B) //true
当数据超出范围就会失去精度,达不到咱们预期的后果。
BigInt横空出世,能够在规范JS中执行对大整数的算术运算,不用放心精度损失危险
创立BigInt数据类型的形式非常简单,在整数前面追加n即可,或者通过BigInt()进行创立实例
const bigint = 999999999999999999nconst bigintByMethod = BigInt('999999999999999999')console.log(bigint) //999999999999999999nconsole.log(bigintByMethod) //999999999999999999nconsole.log(bigint === bigintByMethod) //true//布尔值console.log(BigInt(true)) //1nconsole.log(BigInt(false)) //0nconsole.log(typeof bigint) //"bigint"
BigInt 与 Number是两种数据类型,无奈进行运算,能够进行大小比拟
console.log(88n == 88) //trueconsole.log(88n === 88) //falseconsole.log(88n+1) //Error =>Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
BigInt之间,除了一元加号(+)运算符外,其余均可用于BigInt
console.log(1n + 2n) //3nconsole.log(1n - 2n) //-1nconsole.log(+ 1n) //Uncaught TypeError: Cannot convert a BigInt value to a numberconsole.log(- 1n) //-1nconsole.log(10n * 20n) //200nconsole.log(23n%10n) //3nconsole.log(20n/10n) //2n......
须要留神的是,除法运算符会主动向下舍入到最靠近的整数
console.log(25n / 10n) //2nconsole.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 5undefined ?? 5 // return 5false ?? 5 //return falseNaN ?? 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 => { //模块相干操作})//awaitconst getModule = await import("/module/sneaker/test.js")//通过async awaitconst 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]/gconst 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//WebworkerglobalThis === self //true//NodeglobalThis === global //true
从此实现全局对象的大一统!
Module Namespace Exports 导入特定命名空间
export * as ns from './module//等同于import * as ns from './module'export {ns}
导入特定命名空间实则并没有导入模块,只是对模块进行转发,导致在此模块中不可间接应用此模块
参考
- ecma-262
- MDN
最初
个性很多但有的很乏味,比方可选链和空位合并运算符,屡试不爽,至于有多爽,你试了才晓得。新个性平时不写还是容易疏忽淡忘的,倡议平时能够下意识的常常回顾使用,一起学习一起成长。
本文首发公众号【前端公虾米】,如有谬误,还望分割我指出【y3517320520】