ES11规范于今年的年初完成,引入了许多新标准,本文讲着重研究下其中几个实用且有趣的新标准
严格限制一些用于内部使用的Class变量,只须要在变量前添加#,就可使其成为私有变量,而且没法在class外部直接访问javascript
下面咱们以一个简单的前端
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的公共方法进行统一修改java
假设目前射手携带了狂暴技能,提高了10%伤害,咱们能够经过setAggressivity来修改攻击力正则表达式
let aggressivity = parseInt(hurt * 1.1) shooter.setAggressivity(aggressivity) console.log(shooter.getHurt()) // 110
谈及这个新特性以前,咱们先简单回顾下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结果状态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,表明着失败的缘由async
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) { // 这里代码块不会执行 }
新增一个逻辑运算符??,处理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) ?? "一块儿学习" //"一块儿学习"
平常开发中,很多开发者会碰到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
在标准的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() } }
基于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]
这是为了提供一种访问全局对象的标准方法。
在浏览器中,咱们可使用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
今后实现全局对象的大一统!
export * as ns from './module //等同于 import * as ns from './module' export {ns}
导入特定命名空间实则并无导入模块,只是对模块进行转发,致使在此模块中不可直接使用此模块
特性不少但有的颇有趣,好比可选链和空位合并运算符,屡试不爽,至于有多爽,你试了才知道。新特性日常不写仍是容易忽略淡忘的,建议日常能够下意识的常常回顾运用,一块儿学习一块儿成长。
本文首发公众号【前端公虾米】,若有错误,还望联系我指出【y3517320520】