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 相关文章推荐
js中将多个语句写成一个语句的两种方法小结
Dec 08 Javascript
JQuery 动画卷页 返回顶部 动画特效(兼容Chrome)
Feb 15 Javascript
调试Javascript代码(浏览器F12及VS中debugger关键字)
Jan 25 Javascript
jquery实现像栅栏一样左右滑出式二级菜单效果代码
Aug 24 Javascript
跟我学习javascript的undefined与null
Nov 17 Javascript
通用无限极下拉菜单的实现代码
May 31 Javascript
利用JavaScript阻止表单提交的两种方法
Aug 11 Javascript
关于Angular2 + node接口调试的解决方案
May 28 Javascript
AngularJs+Bootstrap实现漂亮的计算器
Aug 10 Javascript
vue2使用keep-alive缓存多层列表页的方法
Sep 21 Javascript
JS 实现发送短信验证码的“59秒后重新发送验证短信”功能
Aug 23 Javascript
详解vue 组件的实现原理
Nov 12 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
3种平台下安装php4经验点滴
2006/10/09 PHP
PHP入门速成教程
2007/03/19 PHP
php教程之phpize使用方法
2014/02/12 PHP
PHP实现数据分页显示的简单实例
2016/05/26 PHP
PHP记录和读取JSON格式日志文件
2016/07/07 PHP
Yii Framework框架开发微信公众平台示例
2020/04/26 PHP
PHP读取文件或采集时解决中文乱码
2021/03/09 PHP
Javascript 自适应高度的Tab选项卡
2011/04/05 Javascript
jquery获取子节点和父节点的示例代码
2013/09/10 Javascript
使用JavaScript 编写简单计算器
2014/11/24 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
jQuery平滑旋转幻灯片特效代码分享
2015/09/07 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
利用node.js爬取指定排名网站的JS引用库详解
2017/07/25 Javascript
写给小白看的JavaScript异步
2017/11/29 Javascript
详解解决Vue相同路由参数不同不会刷新的问题
2018/10/12 Javascript
详解Vue一个案例引发「内容分发slot」的最全总结
2018/12/02 Javascript
微信小程序实现提交input信息到后台的方法示例
2019/01/19 Javascript
ES6 如何改变JS内置行为的代理与反射
2019/02/11 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
vue实现循环滚动列表
2020/06/30 Javascript
vue用elementui写form表单时,在label里添加空格操作
2020/08/13 Javascript
详解Python中for循环的使用
2015/04/14 Python
Pycharm学习教程(2) 代码风格
2017/05/02 Python
python+gdal+遥感图像拼接(mosaic)的实例
2020/03/10 Python
浅谈python多线程和多线程变量共享问题介绍
2020/04/17 Python
Clearly新西兰:购买眼镜、太阳镜和隐形眼镜
2018/04/26 全球购物
String s = new String(“xyz”);创建了几个String Object?
2015/08/05 面试题
数控专业推荐信范文
2013/12/02 职场文书
日本语毕业生自荐信
2014/02/01 职场文书
高中生操行评语
2014/04/25 职场文书
抗洪救灾先进集体事迹材料
2014/05/26 职场文书
三八节活动简报
2015/07/20 职场文书
Redis可视化客户端小结
2021/06/10 Redis
Nginx缓存设置案例详解
2021/09/15 Servers
【海涛dota解说】DCG联赛第一周 LGD VS DH
2022/04/01 DOTA