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 相关文章推荐
使用Chrome调试JavaScript的断点设置和调试技巧
Dec 16 Javascript
使用纯javascript实现放大镜效果
Mar 18 Javascript
javascript实现ecshop搜索框键盘上下键切换控制
Mar 18 Javascript
JavaScript中日期的相关操作方法总结
Oct 24 Javascript
封装属于自己的JS组件
Jan 27 Javascript
BootStrap 下拉菜单点击之后不会出现下拉菜单(下拉菜单不弹出)的解决方案
Dec 14 Javascript
基于JS实现9种不同的面包屑和分布式多步骤导航效果
Feb 21 Javascript
Angular2仿照微信UI实现9张图片上传和预览的示例代码
Oct 19 Javascript
jQuery 导航自动跟随滚动的实现代码
May 30 jQuery
JS获取当前时间的实例代码(昨天、今天、明天)
Nov 13 Javascript
vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果
Apr 08 Javascript
如何自动化部署项目?折腾服务器之旅~
Apr 16 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
session在PHP大型web应用中的使用
2011/06/25 PHP
php数组函数序列之array_flip() 将数组键名与值对调
2011/11/07 PHP
示例详解Laravel重置密码代码重构
2016/08/10 PHP
php+ajax简单实现全选删除的方法
2016/12/06 PHP
详细解读php的命名空间(二)
2018/02/21 PHP
php实现session共享的实例方法
2019/09/19 PHP
javascript之更有效率的字符串替换
2008/08/02 Javascript
js检测网络是否具体连接功能的代码
2014/05/23 Javascript
jQuery中height()方法用法实例
2014/12/24 Javascript
纯javascript判断查询日期是否为有效日期
2015/08/24 Javascript
原生javascript实现自动更新的时间日期
2016/02/12 Javascript
浅谈AngularJs指令之scope属性详解
2016/10/24 Javascript
js实现移动端导航点击自动滑动效果
2017/07/18 Javascript
深入理解基于vue-cli的webpack打包优化实践及探索
2019/10/14 Javascript
js实现图片粘贴到网页
2019/12/06 Javascript
js将日期格式转换为YYYY-MM-DD HH:MM:SS
2020/09/18 Javascript
web.py在SAE中的Session问题解决方法(使用mysql存储)
2015/06/24 Python
Pandas之drop_duplicates:去除重复项方法
2018/04/18 Python
如何利用Python分析出微信朋友男女统计图
2019/01/25 Python
Python button选取本地图片并显示的实例
2019/06/13 Python
python 列表转为字典的两个小方法(小结)
2019/06/28 Python
对Django url的几种使用方式详解
2019/08/06 Python
浅析rem和em和px vh vw和% 移动端长度单位
2016/04/28 HTML / CSS
如何在Canvas中添加事件的方法示例
2019/05/21 HTML / CSS
耐克美国官网:Nike.com
2016/08/01 全球购物
Berghaus官网:户外服装和设备,防水服
2020/01/17 全球购物
学历公证委托书
2014/04/09 职场文书
拉歌口号大全
2014/06/13 职场文书
城市规划应届生推荐信
2014/09/08 职场文书
乡镇镇长个人整改措施
2014/10/01 职场文书
派出所班子党的群众路线对照检查材料思想汇报
2014/10/01 职场文书
物业前台接待岗位职责
2015/04/03 职场文书
高中团支书竞选稿
2015/11/21 职场文书
用Python的绘图库(matplotlib)绘制小波能量谱
2021/04/17 Python
欧元符号 €
2022/02/17 杂记
python自动获取微信公众号最新文章的实现代码
2022/07/15 Python