ES11的那些新特性,你都了解哪些?

ES11特性抢先了解:

  1. 私有变量
  2. Promise.allSettled
  3. BigInt 全新的数据类型
  4. Nullish Coalescing Operator 空位合并运算符
  5. Optional Chaining Operator 可选链运算符
  6. Dynamic Import 动态导入
  7. String.prototype.matchAll 新增matchAll
  8. globalThis 新增全局对象
  9. 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

使用??运算符时,需要注意:

  1. 如果没有括号不能和其他运算符一起使用
  2. 若使用括号包裹则可以组合使用
"关注我" || 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().

但现在,我们有办法改善此类情况了,因为动态导入可以有效的减少未使用代码的编译,可以提高首屏加载速度,按需加载。 那么,为什么我们需要动态导入呢?

  1. 静态导入消耗加载时间,很多模块并非首屏需要渲染
  2. 静态导入会在导入时消耗大量内存
  3. 可能会存在有些模块在加载时不存在
  4. 减少一些有条件依赖的副作用
//通用导入方式
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年加油!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值