网易首页 > 网易号 > 正文 申请入驻

ECMAScript 2017(ES8)新特性简介

0
分享至

简介

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

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

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

Async函数

我们在ES6中提到了generator,Async函数的操作和generator很类似。

我们看下Async的使用:

//Async 函数定义:
async function foo() {}

//Async 函数表达式:
const foo = async function () {};

//Async 方法定义:
let obj = { async foo() {} }

//Async 箭头函数:
const foo = async () => {};

async函数返回的是一个封装的Promise对象:

async function asyncFunc() {
return 123;

asyncFunc()
.then(x => console.log(x));
// 123

如果在函数中抛出异常,则会reject Promise:

async function asyncFunc() {
throw new Error('Problem!');

asyncFunc()
.catch(err => console.log(err));
// Error: Problem!

上面的例子中我们在async函数使用的是同步的代码,如果想要在async中执行异步代码,则可以使用await,注意await只能在async中使用。

await后面接的是一个Promise。如果Promise完成了,那么await被赋值的结果就是Promise的值。

如果Promise被reject了,那么await将会抛出异常。

async function asyncFunc() {
const result = await otherAsyncFunc();
console.log(result);

// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()
.then(result => {
console.log(result);
});
}

我们可以顺序处理异步执行的结果:

async function asyncFunc() {
const result1 = await otherAsyncFunc1();
console.log(result1);
const result2 = await otherAsyncFunc2();
console.log(result2);
}

// Equivalent to:
function asyncFunc() {
return otherAsyncFunc1()
.then(result1 => {
console.log(result1);
return otherAsyncFunc2();
})
.then(result2 => {
console.log(result2);
});
}

也可以并行执行异步结果:

async function asyncFunc() {
const [result1, result2] = await Promise.all([
otherAsyncFunc1(),
otherAsyncFunc2(),
]);
console.log(result1, result2);
}

// Equivalent to:
function asyncFunc() {
return Promise.all([
otherAsyncFunc1(),
otherAsyncFunc2(),
])
.then([result1, result2] => {
console.log(result1, result2);
});
}

最后看下如何处理异常:

async function asyncFunc() {
try {
await otherAsyncFunc();
} catch (err) {
console.error(err);
}
}

// Equivalent to:
function asyncFunc() {
return otherAsyncFunc()
.catch(err => {
console.error(err);
});
}

需要注意的是,如果async中返回的不是Promise,那么将会被封装成为Promise。如果已经是Promise对象的话,则不会被再次封装:

async function asyncFunc() {
return Promise.resolve(123);
}
asyncFunc()
.then(x => console.log(x)) // 123

同样的,如果返回一个rejected的Promise对象,则和抛出异常一样的结果:

async function asyncFunc() {
return Promise.reject(new Error('Problem!'));
}
asyncFunc()
.catch(err => console.error(err)); // Error: Problem!

如果你只是想触发异步方法,但是并不想等待它执行完毕,那么不使用await:

async function asyncFunc() {
const writer = openFile('someFile.txt');
writer.write('hello'); // don’t wait
writer.write('world'); // don’t wait
await writer.close(); // wait for file to close
}
共享内存和原子操作

ES7引入了一个新的构造函数SharedArrayBuffer和命名空间Atomics。

在JS中,除了主线程之外,我们还可以创建worker线程,主线程和worker线程之间的通信是通过postMessage方法来进行的。

但是这样的通信方式并不高效。于是引入了SharedArrayBuffer这样的共享空间,来提升消息传输效率。

// main.js

const worker = new Worker('worker.js');

// To be shared
const sharedBuffer = new SharedArrayBuffer( // (A)
10 * Int32Array.BYTES_PER_ELEMENT); // 10 elements

// Share sharedBuffer with the worker
worker.postMessage({sharedBuffer}); // clone

// Local only
const sharedArray = new Int32Array(sharedBuffer); // (B)

上面的例子中,我们创建了一个SharedArrayBuffer,并将这个SharedArrayBuffer通过postMessage的方式发给worker。

我们知道postMessage是以拷贝的方式来发送消息的,但是这是正确使用共享的方式。

我看下在worker中怎么接收这个Buffer:

// worker.js

self.addEventListener('message', function (event) {
const {sharedBuffer} = event.data;
const sharedArray = new Int32Array(sharedBuffer); // (A)

// ···
});

在worker中,我们将sharedBuffer使用Int32Array封装起来,作为Array而使用。

那么我们考虑一个问题,在使用sharedBuffer的过程中,会出现什么问题呢?

因为是共享的,所以可以在多个worker线程中同时被使用。如果在同时被使用的时候就会出现多线程共享数据的问题,也就是并发的问题。

为了解决并发的问题,我们回想一下在java中特别有一个concurrent包,里面有一些Atomic的类,可以执行原子性操作。

在ES8中,同样引入了Atomics,用来进行SharedArrayBuffer的原子性操作。同时,使用Atomics还可以禁止重排序。

Atomics实际操作的Typed Array:Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array or Uint32Array。

注意,这些Array都是SharedArrayBuffer的封装Array。并且都是Int的Array(目前只支持Int类型)。

首先看下Atomics怎么解决数组的并发写入和读取的问题:

Atomics.load(ta : TypedArray, index) : T
Atomics.store(ta : TypedArray, index, value : T) : T
Atomics.exchange(ta : TypedArray, index, value : T) : T
Atomics.compareExchange(ta : TypedArray, index, expectedValue, replacementValue) : T

load和store可以将ta作为一个整体来操作。

看下使用例子:

// main.js
console.log('notifying...');
Atomics.store(sharedArray, 0, 123);

// worker.js
while (Atomics.load(sharedArray, 0) !== 123) ;
console.log('notified');

Atomics还提供了wait和notity功能:

Atomics.wait(ta: Int32Array, index, value, timeout)
Atomics.wake(ta : Int32Array, index, count)

当ta[index]的值是value的时候,wait将会使worker等待在ta[index]之上。

而wake,则是将等待在ta[index]上的count个worker唤醒。

Atomics还提供了一系列的操作:

Atomics.add(ta : TypedArray, index, value) : T
Atomics.sub(ta : TypedArray, index, value) : T
Atomics.and(ta : TypedArray, index, value) : T
Atomics.or(ta : TypedArray, index, value) : T
Atomics.xor(ta : TypedArray, index, value) : T

它相当于:

ta[index] += value;

Atomic有一个很棒的作用就是构建lock。我们将会在后面的文章中介绍。

Object的新方法

Object提供了两个遍历的新方法entries和values。

Object.entries(value : any) : Array<[string,any]>

entries返回的是一个数组,里面存储的是key-value对:

> Object.entries({ one: 1, two: 2 })
[ [ 'one', 1 ], [ 'two', 2 ] ]

entries给了我们一个遍历Object的方法:

let obj = { one: 1, two: 2 };
for (let [k,v] of Object.entries(obj)) {
console.log(`{JSON.stringify(k)}:{JSON.stringify(v)}`);
}
// Output:
// "one": 1
// "two": 2

我们可以使用entries来创建Map:

let map = new Map(Object.entries({
one: 1,
two: 2,
}));
console.log(JSON.stringify([...map]));
// [["one",1],["two",2]]

同样的,Object还提供了values方法:

Object.values(value : any) : Array

返回的是一个数组,数组中存放的是Object的value。

除此之外,Object还有一个getOwnPropertyDescriptors新方法。

这个方法返回的是Obj中的属性的描述。所谓属性的描述就是指这个属性是否可写,是否可以数之类:

const obj = {
[Symbol('foo')]: 123,
get bar() { return 'abc' },
};
console.log(Object.getOwnPropertyDescriptors(obj));

// Output:
// { [Symbol('foo')]:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true } }

key是Obj中的key,value就是PropertyDescriptors。

虽然在ES6中,Obj已经引入了一个Object.assign()方法用来拷贝properties,但是这个assign只能拷贝具有默认属性值的属性。对于那些具有非默认属性值的属性getters, setters, non-writable properties来说,Object.assign是不能拷贝的。这个时候就需要使用getOwnPropertyDescriptors方法了。

const source = {
set foo(value) {
console.log(value);
}
};
console.log(Object.getOwnPropertyDescriptor(source, 'foo'));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }

const target1 = {};
Object.assign(target1, source);
console.log(Object.getOwnPropertyDescriptor(target1, 'foo'));
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }

可以看到obj就有一个foo属性,它是一个setter。所以使用assign是不能进行拷贝的。

我们看下怎么使用defineProperties和getOwnPropertyDescriptors来进行拷贝:

const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
console.log(Object.getOwnPropertyDescriptor(target2, 'foo'));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }

除了拷贝属性之外,我们还可以拷贝对象:

const clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
String的新方法

String添加了两个新的方法padStart和padEnd。

pad就是填充的意思,我们可以从前面填充也可以从后面填充。我们看下pad的用法:

String.prototype.padStart(maxLength, fillString=' ')
String.prototype.padEnd(maxLength, fillString=' ')

看下具体的使用:

> 'x'.padStart(5, 'ab')
'ababx'
> 'x'.padEnd(5, 'ab')
'xabab'
逗号可以添加到函数的参数列表后面了

在ES8之前,函数的最后一个参数是不允许添加逗号的,但是在ES8中,一切都变得可能。

function foo(
param1,
param2,

我们可以在函数的定义中添加逗号。也可以在函数的调用中添加逗号:

foo(
'abc',
'def',

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
缅甸公判大会多人被执行死刑,罪犯罗飞因超高颜惹网友心疼

缅甸公判大会多人被执行死刑,罪犯罗飞因超高颜惹网友心疼

映射生活的身影
2024-04-25 20:47:59
中医建议:女孩子多戴首饰

中医建议:女孩子多戴首饰

荷兰豆爱健康
2024-04-21 15:36:08
4月23日,人社部召开发布会,迎来养老金四大好消息,挺重要的

4月23日,人社部召开发布会,迎来养老金四大好消息,挺重要的

小强财艺
2024-04-26 21:53:17
意媒:尤文已经与迪格雷戈里奥达成协议,签约5年年薪200万欧

意媒:尤文已经与迪格雷戈里奥达成协议,签约5年年薪200万欧

懂球帝
2024-04-26 16:36:14
《浪姐5》爆意外!万妮达2公尺高空坠落「摔裂尾椎」

《浪姐5》爆意外!万妮达2公尺高空坠落「摔裂尾椎」

楚门记
2024-04-26 09:03:45
同样是归化!印尼教科书般操作,全年龄归化,掀翻亚洲第3、4

同样是归化!印尼教科书般操作,全年龄归化,掀翻亚洲第3、4

小金体坛大视野
2024-04-26 13:28:33
谁的供应商在搞理想汽车?

谁的供应商在搞理想汽车?

蓝鲸财经
2024-04-26 10:32:08
戚薇能不能别营销这个人设了,真的看腻了

戚薇能不能别营销这个人设了,真的看腻了

娱乐的小灶
2024-04-25 20:57:53
笑死我了,这照片是我看别人发的,我的篮球脏了,不纯粹了

笑死我了,这照片是我看别人发的,我的篮球脏了,不纯粹了

涛涛生活搞笑
2024-04-27 00:38:54
假设是中国和北约开战,以解放军的实力,可能比俄军打得更好吗?

假设是中国和北约开战,以解放军的实力,可能比俄军打得更好吗?

小琪国际
2024-04-17 13:02:43
大轮换!皇马vs皇社首发:居勒尔首次联赛先发,米利唐出战

大轮换!皇马vs皇社首发:居勒尔首次联赛先发,米利唐出战

直播吧
2024-04-27 01:16:48
再看一遍德布劳内复刻范佩西名场面 打入英超生涯首粒头球

再看一遍德布劳内复刻范佩西名场面 打入英超生涯首粒头球

直播吧
2024-04-26 09:46:38
减持美债1644亿,吃进黄金2800吨,我们给耶伦,送上了一份惊喜

减持美债1644亿,吃进黄金2800吨,我们给耶伦,送上了一份惊喜

蓝色海边
2024-04-26 17:54:18
中国银行浙江省分行原党委书记、行长郭心刚,被查

中国银行浙江省分行原党委书记、行长郭心刚,被查

新京报政事儿
2024-04-26 18:47:09
森林狼按下了重置按钮,安东尼·爱德华兹在季后赛的超进化

森林狼按下了重置按钮,安东尼·爱德华兹在季后赛的超进化

绿茵新星
2024-04-26 23:30:25
清空弹夹:乌克兰连发16枚海马斯导弹!英国宣布最大援乌计划

清空弹夹:乌克兰连发16枚海马斯导弹!英国宣布最大援乌计划

项鹏飞
2024-04-23 15:58:07
欺凌何以至此?长沙初三女生被打事件调查

欺凌何以至此?长沙初三女生被打事件调查

澎湃新闻
2024-04-26 10:00:32
G4广州71-93输新疆遭淘汰 球员评分:1人满分,2人及格,6人崩盘

G4广州71-93输新疆遭淘汰 球员评分:1人满分,2人及格,6人崩盘

篮球资讯达人
2024-04-27 01:28:34
神十八发射取得圆满成功;河南6市纪委监委通报

神十八发射取得圆满成功;河南6市纪委监委通报

夏天使娱乐
2024-04-26 20:16:36
上海半马,又有人狂拿25支能量胶:底线呢?

上海半马,又有人狂拿25支能量胶:底线呢?

老王谈跑步
2024-04-26 15:41:43
2024-04-27 02:24:49
flydean程序那些事
flydean程序那些事
最通俗的解读,最深刻的干货!
356文章数 438关注度
往期回顾 全部

科技要闻

车展观察|德系日系绝不能放弃中国市场

头条要闻

官方回应环卫工用电子秤测灰尘:正常作业达标有奖励

头条要闻

官方回应环卫工用电子秤测灰尘:正常作业达标有奖励

体育要闻

还得等!记者:恩昆库本周尝试参加训练 但又被退回医疗中心

娱乐要闻

金靖回应不官宣恋情结婚的原因

财经要闻

贾跃亭,真他娘是个人才

汽车要闻

2024北京车展 比亚迪的自驱力让对手紧追猛赶

态度原创

家居
艺术
本地
公开课
军事航空

家居要闻

光影之间 空间暖意打造生活律动

艺术要闻

画廊周北京迎来第八年, “漂留” 主题聚集 30 余家艺术机构与 40 场展览

本地新闻

蛋友碰碰会空降西安!5.1山海境等你!

公开课

睡前进食会让你发胖吗?

军事要闻

以军称已完成对拉法地面军事行动准备工作

无障碍浏览 进入关怀版