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 相关文章推荐
使用jquery实现图文切换效果另加特效
Jan 20 Javascript
JS保留小数点(四舍五入、四舍六入)实现思路及实例
Apr 25 Javascript
JQuery 控制内容长度超出规定长度显示省略号
May 23 Javascript
Bootstrap每天必学之面板
Nov 30 Javascript
前端jquery部分很精彩
May 03 Javascript
JQuery解析XML数据的几个简单实例
May 18 Javascript
js将table的每个td的内容自动赋值给其title属性的方法
Oct 13 Javascript
JS 60秒后重新发送验证码的实例讲解
Jul 26 Javascript
vue-router两种模式区别及使用注意事项详解
Aug 01 Javascript
在react项目中使用antd的form组件,动态设置input框的值
Oct 24 Javascript
利用node.js开发cli的完整步骤
Dec 29 Javascript
Vue接口封装的完整步骤记录
May 14 Vue.js
记一次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
用 Composer构建自己的 PHP 框架之基础准备
2014/10/30 PHP
学习php设计模式 php实现建造者模式
2015/12/07 PHP
JavaScript是否可实现多线程  深入理解JavaScript定时机制
2009/12/22 Javascript
JavaScript Array Flatten 与递归使用介绍
2011/10/30 Javascript
基于Jquery插件开发之图片放大镜效果(仿淘宝)
2011/11/19 Javascript
Javascript简单实现可拖动的div
2013/10/22 Javascript
JS截取字符串常用方法详细整理
2013/10/28 Javascript
jQuery表格列宽可拖拽改变且兼容firfox
2014/09/03 Javascript
js与css实现弹出层覆盖整个页面的方法
2014/12/13 Javascript
js实现的页面加载完毕之前loading提示效果完整示例【附demo源码下载】
2016/08/02 Javascript
详解Nodejs的timers模块
2016/12/22 NodeJs
详解使用angular的HttpClient搭配rxjs
2017/09/01 Javascript
基于wordpress的ajax写法详解
2018/01/02 Javascript
详解vue+vuex+koa2开发环境搭建及示例开发
2018/01/22 Javascript
JS返回页面时自动回滚到历史浏览位置
2018/09/26 Javascript
浅谈让你的代码更简短,更整洁,更易读的ES6小技巧
2018/10/25 Javascript
ES7之Async/await的使用详解
2019/03/28 Javascript
vue 移动端记录页面浏览位置的方法
2020/03/11 Javascript
vue 解决addRoutes多次添加路由重复的操作
2020/08/04 Javascript
[05:59]2018DOTA2国际邀请赛寻真——只为胜利的Secret
2018/08/13 DOTA
[56:21]LGD vs IG 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
[39:53]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第一场 11.19
2020/11/19 DOTA
Python的Bottle框架中实现最基本的get和post的方法的教程
2015/04/30 Python
Android 兼容性问题:java.lang.UnsupportedOperationException解决办法
2017/03/19 Python
用Python编写一个高效的端口扫描器的方法
2018/12/20 Python
java中的控制结构(if,循环)详解
2019/06/26 Python
用python生成与调用cntk模型代码演示方法
2019/08/26 Python
写自荐信有哪些不宜?
2013/10/17 职场文书
毕业生实习鉴定
2013/12/11 职场文书
司机检讨书
2014/02/13 职场文书
公民代理授权委托书
2014/09/24 职场文书
社区党员群众路线教育实践活动心得体会
2014/11/03 职场文书
工作表扬信范文
2015/01/17 职场文书
繁星春水读书笔记
2015/06/30 职场文书
Python基础之hashlib模块详解
2021/05/06 Python
解决flex布局中子项目尺寸不受flex-shrink限制
2022/05/11 HTML / CSS