ES10 特性的完整指南小结

本篇文章主要介绍了ES10 特性的完整指南,分享给大家,具体如下:

ES10 还只是一个草案。但是除了 Object.fromEntries 之外,Chrome 的大多数功能都已经实现了,为什么不早点开始探索呢?当所有浏览器都开始支持它时,你将走在前面,这只是时间问题。

在新的语言特性方面,ES10 不如 ES6 重要,但它确实添加了一些有趣的特性(其中一些功能目前还无法在浏览器中工作: 2019/02/21)

在 ES6 中,箭头函数无疑是最受欢迎的新特性,在 ES10 中会是什么呢?

BigInt -任意精度整数

BigInt 是第七种 原始类型。

BigInt 是一个任意精度的整数。这意味着变量现在可以 表示²⁵³ 数字,而不仅仅是9007199254740992

const b = 1n; // 追加 n 以创建 BigInt

在过去,不支持大于 9007199254740992 的整数值。如果超过,该值将锁定为 MAX_SAFE_INTEGER + 1:

const limit = Number.MAX_SAFE_INTEGER;
⇨ 9007199254740991
limit + 1;
⇨ 9007199254740992
limit + 2;
⇨ 9007199254740992 <--- MAX_SAFE_INTEGER + 1 exceeded
const larger = 9007199254740991n;
⇨ 9007199254740991n
const integer = BigInt(9007199254740991); // initialize with number
⇨ 9007199254740991n
const same = BigInt("9007199254740991"); // initialize with "string"
⇨ 9007199254740991n

typeof

typeof 10;
⇨ 'number'
typeof 10n;
⇨ 'bigint'

等于运算符可用于两种类型之间比较:

10n === BigInt(10);
⇨ true
10n == 10;
⇨ true

数学运算符只能在自己的类型中工作:

200n / 10n
⇨ 20n
200n / 20
⇨ Uncaught TypeError:
 Cannot mix BigInt and other types, use explicit conversions <

-运算符可以操作, + 不可用

-100n
⇨ -100n
+100n
⇨ Uncaught TypeError:
 Cannot convert a BigInt value to a number

当你读到这篇文章的时候,matchAll 可能已经在 Chrome C73 中正式实现了——如果不是,它仍然值得一看。特别是如果你是一个正则表达式(regex)爱好者。

string.prototype.matchAll()

如果您运行谷歌搜索JavaScript string match all,第一个结果将是这样的:如何编写正则表达式“match all”?

最佳结果将建议 String.match 与正则表达式和 /g 一起使用或者带有 /g 的 RegExp.exec 或者带有 /g 的 RegExp.test 。

首先,让我们看看旧规范是如何工作的。

带字符串参数的 String.match 仅返回第一个匹配:

let string = 'Hello';
let matches = string.match('l');
console.log(matches[0]); // "l"

结果是单个 "l"(注意:匹配存储在 matches[0] 中而不是 matches)

“hello”中搜索 "l" 只返回 "l"

将 string.match 与 regex 参数一起使用也是如此:

让我们使用正则表达式 /l/ 找到字符 串“hello” 中的 “l” 字符:

let string = "Hello";
let matches = string.match(/l/);
console.log(matches[0]); // "l"

添加 /g 混合

let string = "Hello";
let ret = string.match(/l/g); // (2) [“l”, “l”];

很好,我们使用 < ES10 方式得到了多个匹配,它一直起作用。

那么为什么要使用全新的 matchAll 方法呢? 在我们更详细地回答这个问题之前,让我们先来看看 捕获组。如果不出意外,你可能会学到一些关于正则表达式的新知识。

正则表达式捕获组

在 regex 中捕获组只是从 () 括号中提取一个模式,可以使用 /regex/.exec(string) 和string.match 捕捉组。

常规捕获组是通过将模式包装在 (pattern) 中创建的,但是要在结果对象上创建 groups 属性,它是: (?<name>pattern)

要创建一个新的组名,只需在括号内附加 ?<name>,结果中,分组 (pattern) 匹配将成为 group.name,并附加到 match 对象,以下是一个实例:

字符串标本匹配:

这里创建了 match.groups.color 和 match.groups.bird :

const string = 'black*raven lime*parrot white*seagull';
const regex = /(?<color>.*?)\*(?<bird>[a-z0-9]+)/g;
while (match = regex.exec(string))
{
 let value = match[0];
 let index = match.index;
 let input = match.input;
 console.log(`${value} at ${index} with '${input}'`);
console.log(match.groups.color);
 console.log(match.groups.bird);
}

需要多次调用 regex.exec 方法来遍历整个搜索结果集。 在每次迭代期间调用.exec 时,将显示下一个结果(它不会立即返回所有匹配项。),因此使用 while 循环。

输出如下:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull

但奇怪的是:

如果你从这个正则表达式中删除 /g,你将永远在第一个结果上创建一个无限循环。这在过去是一个巨大的痛苦。想象一下,从某个数据库接收正则表达式时,你不确定它的末尾是否有 /g,你得先检查一下。

使用 .matchAll() 的好理由

  • 在与捕获组一起使用时,它可以更加优雅,捕获组只是使用 () 提取模式的正则表达式的一部分。
  • 它返回一个迭代器而不是一个数组,迭代器本身是有用的。
  • 迭代器可以使用扩展运算符 (…) 转换为数组。
  • 它避免了带有 /g 标志的正则表达式,当从数据库或外部源检索未知正则表达式并与陈旧的RegEx 对象一起使用时,它非常有用。
  • 使用 RegEx 对象创建的正则表达式不能使用点 (.) 操作符链接。
  • 高级: RegEx 对象更改跟踪最后匹配位置的内部 .lastindex 属性,这在复杂的情况下会造成严重破坏。

.matchAll() 是如何工作的?

让我们尝试匹配单词 hello 中字母 el 的所有实例, 因为返回了迭代器,所以可以使用 for…of 循环遍历它:

// Match all occurrences of the letters: "e" or "l"
let iterator = "hello".matchAll(/[el]/);
for (const match of iterator)
 console.log(match);

这一次你可以跳过 /g, .matchall 方法不需要它,结果如下:

[ 'e', index: 1, input: 'hello' ] // Iteration 1
[ 'l', index: 2, input: 'hello' ] // Iteration 2
[ 'l', index: 3, input: 'hello' ] // Iteration 3

使用 .matchAll() 捕获组示例:

.matchAll 具有上面列出的所有好处。它是一个迭代器,可以用 for…of 循环遍历它,这就是整个语法的不同。

const string = 'black*raven lime*parrot white*seagull';
const regex = /(?<color>.*?)\*(?<bird>[a-z0-9]+)/;
for (const match of string.matchAll(regex)) {
 let value = match[0];
 let index = match.index;
 let input = match.input;
 console.log(`${value} at ${index} with '${input}'`);
console.log(match.groups.color);
 console.log(match.groups.bird);
}

请注意已经没有 /g 标志,因为 .matchAll() 已经包含了它,打印如下:

black*raven at 0 with 'black*raven lime*parrot white*seagull'
black
raven
lime*parrot at 11 with 'black*raven lime*parrot white*seagull'
lime
parrot
white*seagull at 23 with 'black*raven lime*parrot white*seagull'
white
seagull

也许在美学上它与原始正则表达式非常相似,执行while循环实现。但是如前所述,由于上面提到的许多原因,这是更好的方法,移除 /g 不会导致无限循环。

动态导入

现在可以将导入分配给变量:

element.addEventListener('click', async() => {
 const module = await import(`./api-scripts/button-click.js`);
 module.clickEvent();
})

Array.flat()

扁平化多维数组:

let multi = [1,2,3,[4,5,6,[7,8,9,[10,11,12]]]];
multi.flat();    // [1,2,3,4,5,6,Array(4)]
multi.flat().flat();  // [1,2,3,4,5,6,7,8,9,Array(3)]
multi.flat().flat().flat(); // [1,2,3,4,5,6,7,8,9,10,11,12]
multi.flat(Infinity);  // [1,2,3,4,5,6,7,8,9,10,11,12]

Array.flatMap()

let array = [1, 2, 3, 4, 5];
array.map(x => [x, x * 2]);

let array = [1, 2, 3, 4, 5];
array.map(x => [x, x * 2]);

结果:

[Array(2), Array(2), Array(2), Array(2), Array(2)]
0: (2) [1, 2]
1: (2) [2, 4]
2: (2) [3, 6]
3: (2) [4, 8]
4: (2) [5, 10]

使用 flatMap 方法:

array.flatMap(v => [v, v * 2]);
[1, 2, 2, 4, 3, 6, 4, 8, 5, 10]

Object.fromEntries()

将键值对列表转换为对象:

let obj = { apple : 10, orange : 20, banana : 30 };
let entries = Object.entries(obj);
entries;
(3) [Array(2), Array(2), Array(2)]
 0: (2) ["apple", 10]
 1: (2) ["orange", 20]
 2: (2) ["banana", 30]
let fromEntries = Object.fromEntries(entries);
{ apple: 10, orange: 20, banana: 30 }

String.trimStart() 与 String.trimEnd()

let greeting = "  Space around  ";
greeting.trimEnd(); // "  Space around";
greeting.trimStart(); // "Space around  ";

格式良好的 JSON.stringify()

此更新修复了字符 U+D800 到 U+DFFF 的处理,有时可以进入 JSON 字符串。 这可能是一个问题,因为 JSON.stringify 可能会将这些数字格式化为没有等效 UTF-8 字符的值, 但 JSON 格式需要 UTF-8 编码。

解析方法使用格式良好的JSON字符串,如:

'{ “prop1” : 1, "prop2" : 2 }'; // A well-formed JSON format string

注意,要创建正确 JSON 格式的字符串,绝对需要在属性名周围加上双引号。缺少或任何其他类型的引号都不会生成格式良好的JSON。

'{ “prop1” : 1, "meth" : () => {}}'; // Not JSON format string

JSON 字符串格式与 Object Literal 不同,后者看起来几乎一样,但可以使用任何类型的引号括住属性名,也可以包含方法(JSON格式不允许使用方法):

let object_literal = { property: 1, meth: () => {} };

不管怎样,一切似乎都很好。第一个示例看起来是兼容的。但它们也是简单的例子,大多数情况下都能顺利地工作!

U+2028 和 U+2029 字符

问题是, ES10 之前的 EcmaScript 实际上并不完全支持 JSON 格式。前 ES10 时代不接受未转义行分隔符 U+2028 和段落分隔符 U+2029 字符:

对于 U+D800 - U+DFFF 之间的所有字符也是如此

如果这些字符潜入 JSON 格式的字符串(假设来自数据库记录),你可能会花费数小时试图弄清楚为什么程序的其余部分会产生解析错误。

因此,如果你传递 eval 这样的字符串 “console.log(' hello ')”,它将执行 JavaScript语句 (通过尝试将字符串转换为实际代码),也类似于 JSON.parse 将处理你的 JSON 字符串的方式。

稳定的 Array.prototype.sort()

V8 之前的实现对包含10个以上项的数组使用了一种不稳定的快速排序算法。

一个稳定的排序算法是当两个键值相等的对象在排序后的输出中出现的顺序与在未排序的输入中出现的顺序相同时。

但情况不再是这样了,ES10 提供了一个稳定的数组排序:

var fruit = [
 { name: "Apple",  count: 13, },
 { name: "Pear",  count: 12, },
 { name: "Banana",  count: 12, },
 { name: "Strawberry", count: 11, },
 { name: "Cherry",  count: 11, },
 { name: "Blackberry", count: 10, },
 { name: "Pineapple", count: 10, }
];
// 创建排序函数:
let my_sort = (a, b) => a.count - b.count;
// 执行稳定的ES10排序:
let sorted = fruit.sort(my_sort);
console.log(sorted);

控制台输出(项目以相反的顺序出现):

新的Function.toString()

函数是对象,并且每个对象都有一个 .toString() 方法,因为它最初存在于Object.prototype.toString() 上。 所有对象(包括函数)都是通过基于原型的类继承从它继承的。

这意味着我们以前已经有 funcion.toString() 方法了。

但是 ES10 进一步尝试标准化所有对象和内置函数的字符串表示。 以下是各种新案例:

典型的例子:

function () { console.log('Hello there.'); }.toString();

控制台输出(函数体的字符串格式:)

⇨ function () { console.log('Hello there.'); }

下面是剩下的例子:

直接在方法名 .toString()

Number.parseInt.toString();
⇨ function parseInt() { [native code] }

绑定上下文:

function () { }.bind(0).toString();
⇨ function () { [native code] }

内置可调用函数对象:

Symbol.toString();
⇨ function Symbol() { [native code] }

动态生成的函数:

function* () { }.toString();
⇨ function* () { }

prototype.toString

Function.prototype.toString.call({});
⇨ Function.prototype.toString requires that 'this' be a Function"

可选的 Catch Binding

在过去,try/catch 语句中的 catch 语句需要一个变量。 try/catch 语句帮助捕获终端级别的错误:

try {
 // Call a non-existing function undefined_Function
 undefined_Function("I'm trying");
}
catch(error) {
 // Display the error if statements inside try above fail
 console.log( error ); // undefined_Function is undefined
}

在某些情况下,所需的错误变量是未使用的:

try {
 JSON.parse(text); // <--- this will fail with "text not defined"
 return true; <--- exit without error even if there is one
}
catch (redundant_sometmes) <--- this makes error variable redundant
{
 return false;
}

编写此代码的人通过尝试强制 true 退出 try 子句。但是,这并不是实际发生的情况

(() => {
 try {
  JSON.parse(text)
  return true
 } catch(err) {
  return false
 }
})()
=> false

在 ES10 中,捕获错误的变量是可选的

现在可以跳过错误变量:

try {
 JSON.parse(text);
 return true;
}
catch
{
 return false;
}

目前还无法测试上一个示例中的 try 语句的结果,但一旦它出来,我将更新这部分。

标准化 globalThis 对象

这在ES10之前, globalThis 还没有标准化。

在产品代码中,你可以自己编写这个怪物,在多个平台上“标准化”它:

var getGlobal = function () {
 if (typeof self !== 'undefined') { return self; }
 if (typeof window !== 'undefined') { return window; }
 if (typeof global !== 'undefined') { return global; }
 throw new Error('unable to locate global object');
};

但即使这样也不总是奏效。因此,ES10 添加了 globalThis 对象,从现在开始,该对象用于在任何平台上访问全局作用域:

// 访问全局数组构造函数
globalThis.Array(0, 1, 2);
⇨ [0, 1, 2]

// 类似于 ES5 之前的 window.v = { flag: true }
globalThis.v = { flag: true };

console.log(globalThis.v);
⇨ { flag: true }

Symbol.description

description 是一个只读属性,它返回 Symbol 对象的可选描述。

let mySymbol = 'My Symbol';
let symObj = Symbol(mySymbol);
symObj; // Symbol(My Symbol)
symObj.description; // "My Symbol"

Hashbang 语法

也就是 unix 用户熟悉的 shebang。它指定一个解释器(什么将执行JavaScript文件?)。

ES10标准化,我不会对此进行详细介绍,因为从技术上讲,这并不是一个真正的语言特性,但它基本上统一了 JavaScript 在服务器端的执行方式。

$ ./index.js

代替

$ node index.js

ES10类:private、static 和 公共成员

新的语法字符 #octothorpe(hash tag)现在用于直接在类主体的范围内定义变量,函数,getter 和 setter ......以及构造函数和类方法。

下面是一个毫无意义的例子,它只关注新语法:

class Raven extends Bird {
#state = { eggs: 10};
// getter
 get #eggs() {
  return state.eggs;
 }
// setter
 set #eggs(value) {
  this.#state.eggs = value;
 }
#lay() {
  this.#eggs++;
 }
constructor() {
  super();
  this.#lay.bind(this);
 }
#render() {
  /* paint UI */
 }
}

老实说,我认为这会让语言更难读。

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 简单谈谈ES6的六个小特性

    前言 本文主要针对ES6做一个简要介绍,也许你还不知道ES6是什么, 实际上, 它是一种新的JavaScript规范.在这个大家都很忙碌的时代,如果你想对ES6有一个快速的了解,那么请继续往下读,去了解当今最流行的编程语言JavaScript最新一代的六大特性. 过去一年ES6带来了十足的进步,下面是6个我最喜欢的JS新增特性. 一.Object[key] 有时候不能在对象变量声明时设置所有的key/value,所以得再声明之后添加key/value. let myKey = 'key3'; l

  • ES6中非常实用的新特性介绍

    ECMAScript 6离我们越来越近了,作为它最重要的方言,Javascript也即将迎来语法上的重大变革,InfoQ特开设"深入浅出ES6"专栏,来看一下ES6将给我们带来哪些新内容. 写在前面 ES6 已经提交给 Ecma 大会审查了,也就是说,我们将迎来一大波 javascript 的最新标准,还有一些语法糖.ES6 中有很多值得我们关注的东西,下面是我发现的一些我们最常用的一些新特性,进行记录一下. 1. for-of循环 这个东西用来循环数组很爽,原因呢,是因为它弥补了目前

  • ES10 特性的完整指南小结

    本篇文章主要介绍了ES10 特性的完整指南,分享给大家,具体如下: ES10 还只是一个草案.但是除了 Object.fromEntries 之外,Chrome 的大多数功能都已经实现了,为什么不早点开始探索呢?当所有浏览器都开始支持它时,你将走在前面,这只是时间问题. 在新的语言特性方面,ES10 不如 ES6 重要,但它确实添加了一些有趣的特性(其中一些功能目前还无法在浏览器中工作: 2019/02/21) 在 ES6 中,箭头函数无疑是最受欢迎的新特性,在 ES10 中会是什么呢? Big

  • Git Submodule使用完整教程(小结)

    自从看了蒋鑫的<Git权威指南>之后就开始使用Git Submodule功能,团队也都熟悉了怎么使用,多个子系统(模块)都能及时更新到最新的公共资源,把使用的过程以及经验和容易遇到的问题分享给大家. Git Submodule功能刚刚开始学习可能觉得有点怪异,所以本教程把每一步的操作的命令和结果都用代码的形式展现给大家,以便更好的理解. 1.对于公共资源各种程序员的处理方式 每个公司的系统都会有一套统一的系统风格,或者针对某一个大客户的多个系统风格保持统一,而且如果风格改动后要同步到多个系统中

  • .Net Core 2.2升级3.1的避坑指南(小结)

    写在前面 微软在更新.Net Core版本的时候,动作往往很大,使得每次更新版本的时候都得小心翼翼,坑实在是太多.往往是悄咪咪的移除了某项功能或者组件,或者不在支持XX方法,这就很花时间去找回需要的东西了,下面是个人在迁移.Net Core WebApi项目过程中遇到的问题汇总: 开始迁移 1. 修改*.csproj项目文件 <TargetFramework>netcoreapp2.2</TargetFramework> 修改为 <TargetFramework>net

  • dockerfile-maven-plugin使用指南小结

    目录 pom配置 setting.xml配置 登录情况 需要登录 无需登录 maven多模块情况配置 jenkins jenkins服务器安装docker 修改jenkins项目配置 最近在将应用部署到容器平台,需要在打包时生成docker镜像,在网上首先搜到了docker-maven-plugin这个插件,但使用起来很麻烦,在maven和dockfile都要做很多额外的配置.后来在官方Github看到作者推荐使用dockerfile-maven-plugin这个新的插件,于是替换成这个,但这个

  • Docker部署项目完全使用指南(小结)

    目录 环境准备 Docker安装启动 Java环境安装 Docker远程访问配置 Docker重启 IDEA配置Docker 项目配置 配置Dockerfile文件 Docker配置 Maven打包生成Docker镜像 总结 Linux操作命令 Docker操作命令 环境准备 Docker安装启动 检查系统内核是否满足3.10及以上版本: uname -r 升级内核软件包: yum update 使用yum安装Docker: yum install docker 启动Docker: system

  • java日期格式化YYYY-MM-dd遇坑指南小结

    前几天写日期格式化工具类,自己做测试的时候,无意中发现一个问题,如果把format参数设置成YYYY-MM-DD,输出的结果很奇怪. Date result1 = string2Date("2016-12-15", "yyyy-MM-dd"); System.out.println(result1); Date result2 = string2Date("2016-12-15", "YYYY-MM-DD"); System.

  • React Router v4 入坑指南(小结)

    距离React Router v4 正式发布也已经过去三个月了,这周把一个React的架子做了升级,之前的路由用的还是v2.7.0版的,所以决定把路由也升级下,正好"尝尝鲜"... 江湖传言,目前官方同时维护 2.x 和 4.x 两个版本.(ヾ(。ꏿ﹏ꏿ)ノ゙咦,此刻相信机智如我的你也会发现,ReactRouter v3 去哪儿了?整丢了??巴拉出锅了???敢不敢给我个完美的解释!?)事实上 3.x 版本相比于 2.x 并没有引入任何新的特性,只是将 2.x 版本中部分废弃 API 的

  • Vue中jsx不完全应用指南小结

    前言:文章不介绍任务背景知识,没有原理说明,偏向于实践的总结和经验分享. 文章所有的代码是基于Vue CLI 3.x版本,不会涉及到一步步通过Webpack来配置JSX所需要的知识点. 在使用Vue开发项目时绝大多数情况下都是使用模板来写HTML,但是有些时候页面复杂又存在各种条件判断来显示/隐藏和拼凑页面内容,或者页面中很多部分存在部分DOM结构一样的时候就略显捉襟见肘,会写大量重复的代码,会出现单个.vue文件过长的情况,这个时候我们就需要更多的代码控制,这时候可以使用渲染函数. 渲染函数想

  • Java 8 新特性终极版指南详解

    前言: Java 8已经公布有一段时间了,种种迹象表明Java 8是一个有重大改变的发行版.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java 8 – Lambdas and Concurrency.Java 8 Date Time API Tutorial : LocalDateTime和Abstract Class Versus Interface in the JDK 8 Era.本文还参考了一些其他资料,例如:15 Must

  • AndroidStudio升级到3.0的新特性和注意事项小结

     概述 谷歌发布Android Studio3.0正式版已经有一段时间了,最近抽空升级了一下,也踩了一些坑.特地记录一下.作为开发者第一时间体验谷歌带来的新特性是很有必要的.当然为了项目稳定性,也要根据实际情况决定是否升级相关插件 升级 从已有的IDE升级,无非就是File->Settings->Appearance&Behavior->Updates,这里可以选择升级渠道:Canary(金丝雀)Dev(开发版)Beta(Beta版)Stable(稳定版),以及是否使用安全链接.

随机推荐