精读《What's new in javascript》
1. 引言
本周精读的内容是:Google I/O 19。
2019 年 Google I/O 介绍了一些激动人心的 JS 新特性,这些特性有些已经被主流浏览器实现,并支持 polyfill,有些还在草案阶段。
我们可以看到 JS 语言正变得越来越严谨,不同规范间也逐渐完成了闭环,而且在不断吸纳其他语言的优秀特性,比如 WeakRef,让 JS 在成为使用范围最广编程语言的同时,也越成为编程语言的集大成者,让我们有信心继续跟随 JS 生态,不用被新生的小语种分散精力。
2. 精读
本视频共介绍了 16 个新特性。
private class fields
私有成员修饰符,用于 Class:
class IncreasingCounter {
#count = 0;
get value() {
return this.#count;
}
increment() {
this.#count++;
}
}
通过 #
修饰的成员变量或成员函数就成为了私有变量,如果试图在 Class 外部访问,则会抛出异常:
const counter = new IncreasingCounter()
counter.#count
// -> SyntaxError
counter.#count = 42
// -> SyntaxError
虽然 #
这个关键字被吐槽了很多次,但结论已经尘埃落定了,只是个语法形式而已,不用太纠结。
目前仅 Chrome、Nodejs 支持。
Regex matchAll
正则匹配支持了 matchAll
API,可以更方便进行正则递归了:
const string = 'Magic hex number: DEADBEEF CAFE'
const regex = /\b\p{ASCII_Hex_Digit}+\b/gu/
for (const match of string.matchAll(regex)) {
console.log(match)
}
// Output:
// ['DEADBEEF', index: 19, input: 'Magic hex number: DEADBEEF CAFE']
// ['CAFE', index: 28, input: 'Magic hex number: DEADBEEF CAFE']
相比以前在 while
语句里循环正则匹配,这个 API 真的是相当的便利。And more,还顺带提到了 Named Capture Groups
,这个在之前的 精读《正则 ES2018》 中也有提到,具体可以点过去阅读,也可以配合 matchAll
一起使用。
Numeric literals
大数字面量的支持,比如:
1234567890123456789 * 123;
// -> 151851850485185200000
这样计算结果是丢失精度的,但只要在数字末尾加上 n
,就可以正确计算大数了:
1234567890123456789n * 123n;
// -> 151851850485185185047n
目前 BigInt 已经被 Chrome、Firefox、Nodejs 支持。
BigInt formatting
为了方便阅读,大数还支持了国际化,可以适配成不同国家的语言表达形式:
const nf = new Intl.NumberFormat("fr");
nf.format(12345678901234567890n);
// -> '12 345 678 901 234 567 890'
记住 Intl
这个内置变量,后面还有不少国际化用途。
同时,为了方便程序员阅读代码,大数还支持带下划线的书写方式:
const nf = new Intl.NumberFormat("fr");
nf.format(12345678901234567890n);
// -> '12 345 678 901 234 567 890'
目前已经被 Chrome、Firefox、Nodejs 支持。
flat & flatmap
等价于 lodash flatten 功能:
const array = [1, [2, [3]]];
array.flat();
// -> [1, 2, [3]]
还支持自定义深度,如果支持 Infinity
无限层级:
const array = [1, [2, [3]]];
array.flat(Infinity);
// -> [1, 2, 3]
这样我们就可以配合 .map
使用:
[2, 3, 4].map(duplicate).flat();
因为这个用法太常见,js 内置了 flatMap
函数代替 map
,与上面的效果是等价的:
[2, 3, 4].flatMap(duplicate);
目前已经被 Chrome、Firefox、Safari、Nodejs 支持。
fromEntries
fromEntries
是 Object.fromEntries
的语法,用来将对象转化为数组的描述:
const object = { x: 42, y: 50, abc: 9001 };
const entries = Object.entries(object);
// -> [['x', 42], ['y', 50]]
这样就可以对对象的 key 与 value 进行加工处理,并通过 fromEntries
API 重新转回对象:
const object = { x: 42, y: 50, abc: 9001 }
const result Object.fromEntries(
Object.entries(object)
.filter(([ key, value]) => key.length === 1)
.map(([ key, value ]) => [ key, value * 2])
)
// -> { x: 84, y: 100 }
不仅如此,还可以将 object 快速转化为 Map:
const map = new Map(Object.entries(object));
目前已经被 Chrome、Firefox、Safari、Nodejs 支持。
Map to Object conversion
fromEntries
建立了 object 与 map 之间的桥梁,我们还可以将 Map 快速转化为 object:
const objectCopy = Object.fromEntries(map);
目前已经被 Chrome、Firefox、Safari、Nodejs 支持。
globalThis
业务代码一般不需要访问全局的 window 变量,但是框架与库一般需要,比如 polyfill。
访问全局的 this 一般会做四个兼容,因为 js 在不同运行环境下,全局 this 的变量名都不一样:
const getGlobalThis = () => {
if (typeof self !== "undefined") return self; // web worker 环境
if (typeof window !== "undefined") return window; // web 环境
if (typeof global !== "undefined") return global; // node 环境
if (typeof this !== "undefined") return this; // 独立 js shells 脚本环境
throw new Error("Unable to locate global object");
};
因此整治一下规范也合情合理:
globalThis; // 在任何环境,它就是全局的 this
目前已经被 Chrome、Firefox、Safari、Nodejs 支持。
Stable sort
就是稳定排序结果的功能,比如下面的数组:
const doggos = [
{ name: "Abby", rating: 12 },
{ name: "Bandit", rating: 13 },
{ name: "Choco", rating: 14 },
{ name: "Daisy", rating: 12 },
{ name: "Elmo", rating: 12 },
{ name: "Falco", rating: 13 },
{ name: "Ghost", rating: 14 }
];
doggos.sort((a, b) => b.rating - a.rating);
最终排序结果可能如下:
[
{ name: "Choco", rating: 14 },
{ name: "Ghost", rating: 14 },
{ name: "Bandit", rating: 13 },
{ name: "Falco", rating: 13 },
{ name: "Abby", rating: 12 },
{ name: "Daisy", rating: 12 },
{ name: "Elmo", rating: 12 }
];
也可能如下:
[
{ name: "Ghost", rating: 14 },
{ name: "Choco", rating: 14 },
{ name: "Bandit", rating: 13 },
{ name: "Falco", rating: 13 },
{ name: "Abby", rating: 12 },
{ name: "Daisy", rating: 12 },
{ name: "Elmo", rating: 12 }
];
注意 choco
与 Ghost
的位置可能会颠倒,这是因为 JS 引擎可能只关注 sort
函数的排序,而在顺序相同时,不会保持原有的排序规则。现在通过 Stable sort 规范,可以确保这个排序结果是稳定的。
目前已经被 Chrome、Firefox、Safari、Nodejs 支持。
Intl.RelativeTimeFormat
Intl.RelativeTimeFormat
可以对时间进行语义化翻译:
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
rtf.format(-1, "day");
// -> 'yesterday'
rtf.format(0, "day");
// -> 'today'
rtf.format(1, "day");
// -> 'tomorrow'
rtf.format(-1, "week");
// -> 'last week'
rtf.format(0, "week");
// -> 'this week'
rtf.format(1, "week");
// -> 'next week'
不同语言体系下,format
会返回不同的结果,通过控制 RelativeTimeFormat
的第一个参数 en
决定,比如可以切换为 ta-in
。
Intl.ListFormat
ListFormat
以列表的形式格式化数组:
const lfEnglish = new Intl.ListFormat("en");
lfEnglish.format(["Ada", "Grace"]);
// -> 'Ada and Grace'
可以通过第二个参数指定连接类型:
const lfEnglish = new Intl.ListFormat("en", { type: "disjunction" });
lfEnglish.format(["Ada", "Grace"]);
// -> 'Ada or Grace'
目前已经被 Chrome、Nodejs 支持。
Intl.DateTimeFormat -> formatRange
DateTimeFormat
可以定制日期格式化输出:
const start = new Date(startTimestamp);
// -> 'May 7, 2019'
const end = new Date(endTimestamp);
// -> 'May 9, 2019'
const fmt = new Intl.DateTimeFormat("en", {
year: "numeric",
month: "long",
day: "numeric"
});
const output = `${fmt.format(start)} - ${fmt.format(end)}`;
// -> 'May 7, 2019 - May 9, 2019'
最后一句,也可以通过 formatRange
函数代替:
const output = fmt.formatRange(start, end);
// -> 'May 7 - 9, 2019'
目前已经被 Chrome 支持。
Intl.Locale
定义国际化本地化的相关信息:
const locale = new Intl.Locale("es-419-u-hc-h12", {
calendar: "gregory"
});
locale.language;
// -> 'es'
locale.calendar;
// -> 'gregory'
locale.hourCycle;
// -> 'h12'
locale.region;
// -> '419'
locale.toString();
// -> 'es-419-u-ca-gregory-hc-h12'
目前已经被 Chrome、Nodejs 支持。
Top-Level await
支持在根节点生效 await
,比如:
const result = await doSomethingAsync();
doSomethingElse();
目前还没有支持。
Promise.allSettled/Promise.any
Promise.allSettled
类似 Promise.all
、Promise.any
类似 Promise.race
,区别是,在 Promise reject 时,allSettled
不会 reject,而是也当作 fulfilled 的信号。
举例来说:
const promises = [
fetch("/api-call-1"),
fetch("/api-call-2"),
fetch("/api-call-3")
];
await Promise.allSettled(promises);
即便某个 fetch
失败了,也不会导致 reject
的发生,这样在不在乎是否有项目失败,只要拿到都结束的信号的场景很有用。
对于 Promise.any
则稍有不同:
const promises = [
fetch("/api-call-1"),
fetch("/api-call-2"),
fetch("/api-call-3")
];
try {
const first = await Promise.any(promises);
// Any of ths promises was fulfilled.
console.log(first);
} catch (error) {
// All of the promises were rejected.
}
只要有子项 fulfilled,就会完成 Promise.any
,哪怕第一个 Promise reject 了,而第二个 Promise fulfilled 了,Promise.any
也会 fulfilled,而对于 Promise.race
,这种场景会直接 rejected。
如果所有子项都 rejected,那 Promise.any
也只好 rejected 啦。
目前已经被 Chrome、Firefox 支持。
WeakRef
WeakRef 是从 OC 抄过来的弱引用概念。
为了解决这个问题:当对象被引用后,由于引用的存在,导致对象无法被 GC。
所以如果建立了弱引用,那么对象就不会因为存在的这段引用关系而影响 GC 了!
具体用法是:
const obj = {};
const weakObj = new WeakRef(obj);
使用 weakObj
与 obj
没有任何区别,唯一不同时,obj
可能随时被 GC,而一旦被 GC,弱引用拿到的对象可能就变成 undefined
,所以要做好错误保护。
3. 总结
JS 这几个特性提升了 JS 语言的成熟性、完整性,而且看到其访问控制能力、规范性、国际化等能力有着重加强,解决的都是 JS 最普遍遇到的痛点问题。
那么,这些 JS 特性中,你最喜欢哪一条呢?想吐槽哪一条呢?欢迎留言。
讨论地址是:精读《What's new in javascript》 · Issue #159 · dt-fe/weekly
如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。
关注 前端精读微信公众号
special Sponsors
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
精读《What's new in javascript》的更多相关文章
- 精读《V8 引擎 Lazy Parsing》
1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...
- 深入浏览器工作原理和JS引擎(V8引擎为例)
浏览器工作原理和JS引擎 1.浏览器工作原理 在浏览器中输入查找内容,浏览器是怎样将页面加载出来的?以及JavaScript代码在浏览器中是如何被执行的? 大概流程可观察以下图: 首先,用户在浏览器搜 ...
- [翻译] V8引擎的解析
原文:Parsing in V8 explained 本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划. 动机 我们有个解析器和一个更快的预解析器(~2x), ...
- 一文搞懂V8引擎的垃圾回收
引言 作为目前最流行的JavaScript引擎,V8引擎从出现的那一刻起便广泛受到人们的关注,我们知道,JavaScript可以高效地运行在浏览器和Nodejs这两大宿主环境中,也是因为背后有强大的V ...
- Chrome V8引擎系列随笔 (1):Math.Random()函数概览
先让大家来看一幅图,这幅图是V8引擎4.7版本和4.9版本Math.Random()函数的值的分布图,我可以这么理解 .从下图中,也许你会认为这是个二维码?其实这幅图告诉我们一个道理,第二张图的点的分 ...
- (译)V8引擎介绍
V8是什么? V8是谷歌在德国研发中心开发的一个JavaScript引擎.开源并且用C++实现.可以用于运行于客户端和服务端的Javascript程序. V8设计的初衷是为了提高浏览器上JavaScr ...
- 浅谈Chrome V8引擎中的垃圾回收机制
垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...
- V8引擎嵌入指南
如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...
- 浅谈V8引擎中的垃圾回收机制
最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...
- 深入出不来nodejs源码-V8引擎初探
原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...
随机推荐
- 关于Python你不得不知道的Python语言特点
首先什么是语言?什么是编程? 准确来说是:定义计算机程序的语言,用来向计算机发送指令 个人理解: 语言:是一种交流的工具或者方式.比如我们的汉语普通话.各地的方言.外语中的英语.俄语.日语等.我们 ...
- 【洛谷P3413】萌数
题目大意:求区间 [l,r] 内萌数的个数,其中萌数定义为数位中存在长度至少为 2 的回文子串的数字. 题解:l, r 都是 1000 位级别的数字,显然是一道数位 dp 的题目,暴力直接去世. 发现 ...
- vs2017 mvc 启动时经常出现调用的目标发生异常
1.vs 2017 调试web 程序时老是出现调用的目标发生异常 本人眼拙,基本上看了网站说的一些方法,设置环境变量是无效的,只有一个办法,卸载重装. 1.0 卸载过程 打开计算机-卸载或更改软件- ...
- Redux 聊聊
前言 Redux 是 JavaScript 状态容器,提供可预测化的状态管理. 首先明确一点的就是: Redux并不是React必须的,也没有任何依赖,你可以很自由的将他应用到各种前端框架.jQuer ...
- 8.0.17 MySQL Community Server 二进制手工安装
8.0.17 MySQL Community Server 二进制手工安装 环境简介 操作系统:Centos 6.10 64位目前版本:8.0.17 MySQL Community Server 二进 ...
- react保存用户的输入换行,空格等等
<div dangerouslySetInnerHTML = {{ __html: '接口返回值' }} />
- 【NOIP2016提高A组模拟10.15】算循环
题目 分析 一步步删掉循环, 首先,原式是\[\sum_{i=1}^n\sum_{j=1}^m\sum_{k=i}^n\sum_{l=j}^m\sum_{p=i}^k\sum_{q=j}^l1\] 删 ...
- linux服务器外网内网(双网络)搭建
一共有2台服务器,分别用a,b表示.a双网卡,即有外网也有内网.b只有内网环境.a,b的内网是通过交换机组建.至于外网怎么搭建我就不说了.关键说一说内网是怎么组建的. 如果你对linux不熟悉,对网卡 ...
- codevs 1020 孪生蜘蛛 x
题目描述 Description 在G城保卫战中,超级孪生蜘蛛Phantom001和Phantom002作为第三层防卫被派往守护内城南端一带极为隐秘的通道. 根据防护中心的消息,敌方已经有一只特种飞蛾 ...
- Pollard's Rho算法简单总结
先贴一份代码在这. 最近几天实在是太忙了没时间更新了. 代码 #include <iostream> #include <cstdio> #include <cstdli ...