关于ecmascript:ECMAScript-2018ES9新特性简介

10次阅读

共计 4163 个字符,预计需要花费 11 分钟才能阅读完成。

简介

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));
~~

> 留神,咱们应用的所有的拷贝都是浅拷贝。如果被拷贝的对象外部又有对象的话,拷贝的只是这个对象的援用

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/](http://www.flydean.com/ecmascript-9/)
> 
> 本文起源:flydean 的博客
> 
> 欢送关注我的公众号:「程序那些事」最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

正文完
 0