简介

ES9是ECMA协会在2018年6月发行的一个版本,因为是ECMAScript的第九个版本,所以也称为ES9.

今天我们讲解一下ES9的新特性。

ES9引入了3大特性和2个小的特性,我们接下来一一讲解。

异步遍历

在ES6中,引入了同步iteration的概念,随着ES8中的Async操作符的引用,在ES9中引入了异步遍历的新特性Async iteration。

具体的内容可以参考我之前的文章 ES9的新特性:异步遍历Async iteration

Rest/Spread操作符和对象构建

Rest和Spread的操作符都是 ... , 只不过使用的场景和目的不一样。

rest主要用在对象的解构,目前只支持对象的解构和不确定的参数描述。

Spread主要用在字面量对象的构建上。

下面我们分别来介绍:

Rest

如果用在对象的解构中,除了已经手动指定的属性名之外,rest将会拷贝对象其他的所有可枚举(enumerable)的属性。

const obj = {foo: 1, bar: 2, baz: 3};
const {foo, ...rest} = obj;
// Same as:
// const foo = 1;
// const rest = {bar: 2, baz: 3};

如果用在参数中,rest表示的是所有剩下的参数:

function func({param1, param2, ...rest}) { // rest operator
console.log('All parameters: ',
{param1, param2, ...rest}); // spread operator
return param1 + param2;
}

注意,在Obj字面量中,rest运算符只能放在obj的最顶层,并且只能使用一次,还要放在最后。

const {...rest, foo} = obj; // SyntaxError
const {foo, ...rest1, ...rest2} = obj; // SyntaxError

当然你还可以嵌套使用rest运算符:

const obj = {
foo: {
a: 1,
b: 2,
c: 3,
},
bar: 4,
baz: 5,
};
const {foo: {a, ...rest1}, ...rest2} = obj;
// Same as:
// const a = 1;
// const rest1 = {b: 2, c: 3};
// const rest2 = {bar: 4, baz: 5};

Spread

spread主要被用来展开对象,能够被展开对象的属性一定要是可枚举的enumerable。

> const obj = {foo: 1, bar: 2};
> {...obj, baz: 3}
{ foo: 1, bar: 2, baz: 3 }

如果对象的属性key一样,那么后面属性值会覆盖之前的属性值:

> const obj = {foo: 1, bar: 2, baz: 3};
> {...obj, foo: true}
{ foo: true, bar: 2, baz: 3 }
> {foo: true, ...obj}
{ foo: 1, bar: 2, baz: 3 }

创建和拷贝对象

使用Object.assign和Spread操作符可以很方便的进行对象的拷贝。

我们看一个最简单的对象拷贝的例子:

const clone1 = {...obj};
const clone2 = Object.assign({}, obj);

但是这样的拷贝有个缺点,就是只能拷贝自有的可枚举的属性。

并且拷贝之后对象的prototypes是Object.prototype,也就是说没有继承被拷贝对象的prototype。

> Object.getPrototypeOf(clone1) === Object.prototype
true
> Object.getPrototypeOf(clone2) === Object.prototype
true
> Object.getPrototypeOf({}) === Object.prototype
true

如果想要同时拷贝对象的prototype,则可以这样做:

const clone1 = {__proto__: Object.getPrototypeOf(obj), ...obj};
const clone2 = Object.assign(
Object.create(Object.getPrototypeOf(obj)), obj);

或者指定对象内置的__proto__属性,或者从obj的prtotype创建一个新的对象。

注意,对象内置的__proto__属性只在部分浏览器中支持。

Object.assign和spread只能拷贝可枚举的属性,如果是set,get属性或者想要拷贝属性的attributes(writable, enumerable),那么就需要用到我们之前讲到的Object.getOwnPropertyDescriptors。

const clone1 = Object.defineProperties({},
Object.getOwnPropertyDescriptors(obj)); const clone2 = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
~~ > 注意,我们使用的所有的拷贝都是浅拷贝。如果被拷贝的对象内部又有对象的话,拷贝的只是这个对象的引用 ~~~js
const original = { prop: {} };
const clone = Object.assign({}, original); console.log(original.prop === clone.prop); // true
original.prop.foo = 'abc';
console.log(clone.prop.foo); // abc

Spread和bject.assign() 的区别

assgin在拷贝对象的时候,会调用相应属性的set方法,而spread不会。

举个例子,我们先给Object.prototype定义一个set方法:

Object.defineProperty(Object.prototype, 'foo', {
set(value) {
console.log('SET', value);
},
});
const obj = {foo: 123};

然后看一下拷贝的区别:

> Object.assign({}, obj)
SET 123
{} > { ...obj }
{ foo: 123 }

可以看到assign会触发set方法,而spread不会。

另外,如果对象属性是不可写的,那么assign将会报错,而spread不会。

我们先定义一个不可写的对象:

Object.defineProperty(Object.prototype, 'bar', {
writable: false,
value: 'abc',
});

看下赋值操作:

> const tmp = {};
> tmp.bar = 123;
TypeError: Cannot assign to read only property 'bar' > Object.assign({}, obj)
TypeError: Cannot assign to read only property 'bar' > { ...obj }
{ bar: 123 }

正则表达式

ES9的正则表达式新特性可以参考我的文章 ES9的新特性:正则表达式RegExp

promise.finally

promise除了then和catch方法之外,还引入了新的finally方法。

和java中的finally一样,promise.finally一定会被执行。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

和java一样,我们可以在finally中做一些资源清理的工作:

let connection;
db.open()
.then(conn => {
connection = conn;
return connection.select({ name: 'Jane' });
})
.then(result => {
...
})
···
.catch(error => {
// handle errors
})
.finally(() => {
connection.close();
});

上面的例子中,我们开启了一个数据库的连接,在使用完之后,我们在finally中对其进行close操作。

模板文字和带标签的模板文字

模板文字和带标签的模板文字是在ES6中引入的,在ES9中进行了修正。

我们先看下什么是模本文字,模板文字(Template literals)就是在反引号中输入的文字,在其中可以使用${···})来进行变量的解析,并且还支持回车换行。

const firstName = 'Jane';
console.log(`Hello ${firstName}!
How are you
today?`); // Output:
// Hello Jane!
// How are you
// today?

而带标签的模板文字是指在模板文字之前放上一个函数调用:

String.raw`\u{4B}`
'\u{4B}'

这里String.raw被称为tag function,我们看下raw的定义:

raw(template: TemplateStringsArray, ...substitutions: any[]): string;

上面的代码还可以改写为:

String.raw`\u004B`
'\u004B'

\u{4B}\u004B 都是字符K的unicode表示。

上面的raw其实可以这样表示:

function tagFunc(tmplObj, substs) {
return {
Cooked: tmplObj,
Raw: tmplObj.raw,
};
}

我们可以这样使用:

> tagFunc`\u{4B}`;
{ Cooked: [ 'K' ], Raw: [ '\\u{4B}' ] }

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/ecmascript-9/

本文来源:flydean的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

ECMAScript 2018(ES9)新特性简介的更多相关文章

  1. ECMAScript 2016(ES7)新特性简介

    简介 自从ES6(ECMAScript 2015)在2015年发布以来,ECMAScript以每年一个版本的速度持续向前发展.到现在已经是ECMAScript 2020了. 每个版本都有一些新的特性, ...

  2. ECMAScript 2017(ES8)新特性简介

    目录 简介 Async函数 共享内存和原子操作 Object的新方法 String的新方法 逗号可以添加到函数的参数列表后面了 简介 ES8是ECMA协会在2017年6月发行的一个版本,因为是ECMA ...

  3. ECMAScript 2019(ES10)新特性简介

    简介 ES10是ECMA协会在2019年6月发行的一个版本,因为是ECMAScript的第十个版本,所以也称为ES10. 今天我们讲解一下ES10的新特性. ES10引入了2大特性和4个小的特性,我们 ...

  4. ECMAScript 2020(ES11)新特性简介

    目录 简介 动态imports import.meta export加强 BigInt matchAll() globalThis Promise.allSettled() ??操作符 ?.操作符 总 ...

  5. ECMAScript 2021(ES12)新特性简介

    简介 ES12是ECMA协会在2021年6月发行的一个版本,因为是ECMAScript的第十二个版本,所以也称为ES12. ES12发行到现在已经有一个月了,那么ES12有些什么新特性和不一样的地方呢 ...

  6. 细解JavaScript ES7 ES8 ES9 新特性

    题记:本文提供了一个在线PPT版本,方便您浏览 细解JAVASCRIPT ES7 ES8 ES9 新特性 在线PPT ver 本文的大部分内容译自作者Axel Rauschmayer博士的网站,想了解 ...

  7. ES6新特性简介

    ES6新特性简介 环境安装 npm install -g babel npm install -g babel-node //提供基于node的REPL环境 //创建 .babelrc 文件 {&qu ...

  8. ECMAScript 6新特性简介

    目录 简介 ECMAScript和JavaScript的关系 let和const 解构赋值 数组的扩展 函数的扩展 简介 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言 ...

  9. ES9新特性

    这篇文章主要介绍ES2018(ES9)的新特性, 以及使用方法 JS是一门跨平台的语言, ES6也就是ECMAScript 2015 花费了5年的时间敲定, 是一次非常大的改版, 之后每年都有一个小版 ...

随机推荐

  1. chmod +x vs chmod 755

    chmod +x vs chmod 755 What is the difference between "chmod +x" and "chmod 755"? ...

  2. Prettier All In One

    Prettier All In One .prettierrc.js / .prettierrc / .prettierrc.json module.exports = { singleQuote: ...

  3. Google Tag Manager

    Google Tag Manager SEO https://www.wappalyzer.com/technologies/tag-managers/google-tag-manager/ UTM ...

  4. vue watch & arrow function bug

    vue watch & arrow function bug watch: { GeoJSON: function(newValue, oldValue) { log(`\n\n\nGeoJS ...

  5. 稳定币USDN的算法调控

    在NGK公链的稳定币系统中,USDN的价格有时会出现一定幅度的波动.正如我们会看到USDT有时会是0.99美元,有时是1.01美元一样.那么,要保障USDN在二级市场的价格基本稳定,要如何调节供需呢? ...

  6. React 函数式组件的 Ref 和子组件访问(useImperativeHandle)

    引入:如何调用函数式组件内部的方法 对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例.除此之 ...

  7. 【PY从0到1】 一文掌握Pandas量化进阶

    # 一文掌握Pandas量化进阶 # 这节课学习Pandas更深的内容. # 导入库: import numpy as np import pandas as pd # 制作DataFrame np. ...

  8. InnoDB -- 行记录格式

    本文转载自InnoDB -- 行记录格式 分类 Named File Format InnoDB早期的文件格式(页格式)为Antelope,可以定义两种行记录格式,分别是Compact和Redunda ...

  9. Java并发之CompletionService详解

    CompletionService是什么? 它是JUC包中的一个接口类,默认实现类只有一个ExecutorCompletionService. CompletionService干什么的? 它将异步任 ...

  10. Element-UI使用相关问题

    1.如何修改el-dialog的样式? 要修改dialog的样式不能直接在<style scoped>中修改,这样修改后不会生效.做法是把scoped去掉,然后在dialog标签上自定义一 ...