ES11屡试不爽的新特性,你用上了几个


Posted in Javascript onOctober 21, 2020

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来修改攻击力

ES11屡试不爽的新特性,你用上了几个

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

最后

特性很多但有的很有趣,比如可选链和空位合并运算符,屡试不爽,至于有多爽,你试了才知道。新特性平常不写还是容易忽略淡忘的,建议平常可以下意识的经常回顾运用,一起学习一起成长。

到此这篇关于ES11屡试不爽的新特性,你用上了几个的文章就介绍到这了,更多相关ES11 新特性内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript中数组继承的简单示例
Jul 29 Javascript
JS实现常见的TAB、弹出层效果(TAB标签,斑马线,遮罩层等)
Oct 08 Javascript
再谈JavaScript异步编程
Jan 27 Javascript
Angular 4依赖注入学习教程之Injectable装饰器(六)
Jun 04 Javascript
layui框架中layer父子页面交互的方法分析
Nov 15 Javascript
通过jquery的ajax请求本地的json文件方法
Aug 08 jQuery
利用Bootstrap Multiselect实现下拉框多选功能
Apr 08 Javascript
微信小程序 swiper 组件遇到的问题及解决方法
May 26 Javascript
node中使用log4js4.x版本记录日志的方法
Aug 20 Javascript
微信小程序定义和调用全局变量globalData的实现
Nov 01 Javascript
js实现九宫格抽奖
Mar 19 Javascript
canvas 中如何实现物体的框选
Aug 05 Javascript
记一次vue跨域的解决
Oct 21 #Javascript
解决Vue项目中tff报错的问题
Oct 21 #Javascript
vue-cli3自动消除console.log()的调试信息方式
Oct 21 #Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
Oct 21 #Javascript
vue-cli4使用全局less文件中的变量配置操作
Oct 21 #Javascript
Vue全局使用less样式,组件使用全局样式文件中定义的变量操作
Oct 21 #Javascript
js 图片懒加载的实现
Oct 21 #Javascript
You might like
PHP伪静态Rewrite设置之APACHE篇
2014/07/30 PHP
基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法
2015/12/20 PHP
PHP实现类似于C语言的文件读取及解析功能
2017/09/01 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
tp框架(thinkPHP)实现三次登陆密码错误之后锁定账号功能示例
2018/05/24 PHP
php设计模式之单例模式用法经典示例分析
2019/09/20 PHP
jquery tools之tooltip
2009/07/25 Javascript
js中apply方法的使用详细解析
2013/11/04 Javascript
jquery使用jxl插件导出excel示例
2014/04/14 Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
2014/05/08 Javascript
JavaScript入门基础
2015/08/12 Javascript
详解基于webpack2.x的vue2.x的多页面站点
2017/08/21 Javascript
学习JS中的DOM节点以及操作
2018/04/30 Javascript
jQuery实现下拉菜单动态添加数据点击滑出收起其他功能
2018/06/14 jQuery
如何使用pm2快速将项目部署到远程服务器
2019/03/12 Javascript
JavaScript实现随机点名器实例详解
2019/05/07 Javascript
JavaScript面向对象中接口实现方法详解
2019/07/24 Javascript
vue 遮罩层阻止默认滚动事件操作
2020/07/28 Javascript
tornado框架blog模块分析与使用
2013/11/21 Python
用Python编写分析Python程序性能的工具的教程
2015/04/01 Python
python pandas 组内排序、单组排序、标号的实例
2018/04/12 Python
Python使用post及get方式提交数据的实例
2019/01/24 Python
python如何使用socketserver模块实现并发聊天
2019/12/14 Python
吉列剃须刀美国官网:Gillette美国
2018/07/13 全球购物
为什么需要版本控制?
2013/08/08 面试题
初入社会应届生求职信
2013/11/18 职场文书
党员公开承诺书
2014/03/25 职场文书
青春奉献演讲稿
2014/05/08 职场文书
中标通知书范本
2015/04/17 职场文书
原告离婚代理词
2015/05/23 职场文书
大国崛起英国观后感
2015/06/02 职场文书
付款证明模板
2015/06/19 职场文书
redis 查看所有的key方式
2021/05/07 Redis
Python编程super应用场景及示例解析
2021/10/05 Python
python调用ffmpeg命令行工具便捷操作视频示例实现过程
2021/11/01 Python
使用Nginx+Tomcat实现负载均衡的全过程
2022/05/30 Servers