ES11特性抢先了解:
- 私有变量
- Promise.allSettled
- BigInt 全新的数据类型
- Nullish Coalescing Operator 空位合并运算符
- Optional Chaining Operator 可选链运算符
- Dynamic Import 动态导入
- String.prototype.matchAll 新增matchAll
- globalThis 新增全局对象
- Module Namespace Exports 导入特定命名空间
1. 私有变量
严格限制一些用于内部使用的Class变量,只需要在变量前「添加#」,就可以使其成为私有变量,并且无法在class外部直接访问(以前是private)。
class Dog {
#leg= 2 // 私有变量
constructor (leg){
this.#leg= leg
}
getLeg(){
return this.#leg
}
setLeg(leg){
this.#leg= leg
}
}
const dogOne= new Dog (100)
let number= dogOne.getLeg()
console.log(number) //100
console.log(dogOne.#leg) //Error : Uncaught SyntaxError: Private field '#leg' must be declared in an enclosing class
从上述代码中可以看出,在变量前面加#后,dogOne的实例只能通过getLeg内部函数拿到#leg私有变量,如果使用实例直接访问该变量会报错。
如果想要修改这个私有变量,可以调用内部函数setLeg。
let newNumber = parseInt(number* 2)
dogOne.setLeg(newNumber) // 调用实例对象的setLeg,更改私有变量#leg
console.log(dogOne.getLeg()) // 200
2. Promise.allSettled
在了解这个新特性之前,我们回顾一下Promise的两个api:1. Promise.all 2. Promise.race
Promise.all:可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值
let p1 = new Promise((resolve, reject) => {
resolve('成功1')
})
let p2 = new Promise((resolve, reject) => {
resolve('成功2')
})
let p3 = Promse.reject('失败')
Promise.all([p1, p2]).then((result) => {
console.log(result) //输出 ['成功1', '成功2']
}).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, 1000, '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:不管每个请求是否成功都会返回一个数组,失败的请求的status结果会是rejected。
const promises = [
Promise.reject('a'),
Promise.resolve('b'),
Promise.resolve('c'),
];
Promise.allSettled(promises).then(res =>{
console.log(res)
})
// 打印结果
// [{"status":"rejected","reason":"a"},
// {"status":"fulfilled","value":"b"},
// {"status":"fulfilled","value":"c"}]
返回结果是一个数组,含所有成功与失败的请求。数组每项均含有status属性,值为fulfilled或rejected。 当状态为fulfilled时,表示请求成功,包含一个value,代表着成功的结果。当状态为rejected时,表示请求失败,包含一个reason,代表着失败的原因。
3. BigInt
JS中缺少显式整数类型常常令人困惑。许多编程语言支持多种数字类型,如浮点型、双精度型、整数型和双精度型,但JS却不是这样。在JS中,按照IEEE 754-2008标准的定义,所有数字都以双精度「64位浮点格式」表示。
在此标准下,无法精确表示的非常大的整数将自动四舍五入。确切地说,JS 中的Number类型只能安全地表示-9007199254740991 (-(2^53-1)) 和9007199254740991(2^53-1)之间的整数,任何超出此范围的整数值都可能失去精度。
console.log(0.1 + 0.2) // 0.30000000000000004
当数据超出范围就会失去精度,达不到我们预期的结果。
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(11n == 11) //true
console.log(11n === 11) //false
console.log(11n+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) {} // 这里代码块不会执行
4. Nullish Coalescing Operator 空位合并运算符
新增逻辑运算符??,处理null和undefined,如果左边的值为null或undefined,则返回右边的值,如果不为null或undefined,则返回左边的值。
|| 例子
0 || 5 // return 5
"" || 5 // return 5
"关注我" || '5' //return "关注我"
?? 例子
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) ?? "好的" //"好的"
5. 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
6. 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()
}
}
7. 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]
8. 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')
})
现在我们可以直接使用globalThis来获取全局对象,其实就是把self/window/global进行了统一,一致使用globalThis。
//Browser
globalThis === window //true
//Webworker
globalThis === self //true
//Node
globalThis === global //true
9. Module Namespace Exports 导入特定命名空间
导入特定命名空间实际上并没有导入模块,只是对模块进行转发,导致当前不可直接使用此模块。
export * as ns from './module
//等同于
import * as ns from './module'
export {ns}
最后
因为ES11是今年才出来的,所以还是希望大家可以经常去使用它,才不会今天看转天就忘记。其中有几个在开发中是比较常用到的,比如:空位合并运算符、可选链运算符、动态导入等。
最后的最后
希望大家2021年加油!!!