您的位置:首页 > 其它

ES7、ES8新特性

2017-07-26 11:19 495 查看

概述

JavaScript,作为一门处于高速发展期的开发语言,正在变的越来越完善、稳定。我们必须拥抱这些变化,并且我们需要把ES8加入到我们的技术栈中。

ECMAScript 是标准化的 JavaScript 语言,1997 年发布了第一版,1998 年和 1999 年发布了第二和第三个版本,之后沉寂 了许多年,直到 Ajax 流行起来后标准工作才再次起步,2009 年发布了第五个版本,自 2015 年起每年发布一个版本。现在为开发者所熟知的ES6就是2015年发布的。

ES7新增特性比较少,在这个版本中,ES7只增加了两种新特性:Array.prototype.includes和Exponentiation Operator(求冥运算)。而在最新的ES8版本中,新增的特性比较多,主要包括:Object.values/Object.entries、字符串填充、Object.getOwnPropertyDescriptor、尾随逗号、异步函数、共享内存和原子等。

ES7 新特性

Array.prototype.includes

Array.prototype.includes用法都容易和简单。它是一个替代indexOf,开发人员用来检查数组中是否存在值,indexOf是一种尴尬的使用,因为它返回一个元素在数组中的位置或者-1当这样的元素不能被找到的情况下。所以它返回一个数字,而不是一个布尔值(开发人员需要实施额外的检查)。在ES6,要检查是否存在值,你需要做一些判断,因为他们没有匹配到值,Array.prototype.indexOf返回-1变成了true(转换成true),但是当匹配的元素为0位置时候,该数组包含元素,却变成了false。

let arr = ['react', 'angular', 'vue']

// WRONG
if (arr.indexOf('react')) { // 0 -> evaluates to false, definitely as we expected
console.log('Can use React') // this line would never be executed
}

// Correct
if (arr.indexOf('react') !== -1) {
console.log('Can use React')
}


或者使用一点点hack 位运算符 ~ 使代码更加紧凑一些,因为~(位异或)对任何数字相当于-(a + 1)。

let arr = ['react', 'angular', 'vue']

// Correct
if (~arr.indexOf('react')) {
console.log('Can use React')
}


在ES7中,使用includes代码格式如下:

let arr = ['react', 'angular', 'vue']

// Correct
if (arr.includes('react')) {
console.log('Can use React')
}


let str = 'React Quickly'

// Correct
if (str.toLowerCase().includes('react')) {  // true
console.log('Found "react"')
}


有趣的是,许多JavaScript库已经实现includes或类似功能contains的功能。常见的有:

jQuery: $.inArray

Underscore.js: _.contains

Lodash: .includes (在版本3或者早期版本中是.contains 和 Underscore一样)

CoffeeScript: in 操作(example)

Darf: list.contains (example)

除了增强了可读性语义化,实际上给开发者返回布尔值,而不是匹配的位置。includes也可以在NaN(非数字)使用。最后,includes第二可选参数fromIndex,这对于优化是有好处的,因为它允许从特定位置开始寻找匹配。

上面的说明例子:

console.log([1, 2, 3].includes(2)) // === true)
console.log([1, 2, 3].includes(4)) // === false)
console.log([1, 2, NaN].includes(NaN)) // === true)
console.log([1, 2, -0].includes(+0)) // === true)
console.log([1, 2, +0].includes(-0)) // === true)
console.log(['a', 'b', 'c'].includes('a')) // === true)
console.log(['a', 'b', 'c'].includes('a', 1)) // === false)


Exponentiation Operator

求幂运算大多数是为开发者做一些数学计算,对于3D,VR,SVG还有数据可视化非常有用。在ES6或者早些版本,你不得不创建一个循环,创建一个递归函数或者使用Math.pow。例如,使用Math.pow创建一个递归箭头函数。

calculateExponent = (base, exponent) => base*((--exponent>1)?calculateExponent(base, exponent):base)
console.log(calculateExponent(7,12) === Math.pow(7,12)) // true
console.log(calculateExponent(2,7) === Math.pow(2,7)) // true


而在ES7/ES2016语法规则中,开发者可以使用更短的语法实现求冥运算。

let a = 7 ** 12
let b = 2 ** 7
console.log(a === Math.pow(7,12)) // true
console.log(b === Math.pow(2,7)) // true


许多ES新特性是从其他语言(如CoffeeScript、Ruby)模仿而来。例如,ES7中指数运算符在其他语言的存在形式。

Python: x ** y

CoffeeScript: x ** y

F#: x ** y

Ruby: x ** y

Perl: x ** y

Lua, Basic, MATLAB: x ^ y

ES8

ES8 在上一个版本的基础上增加了很多新特性!ES8标准已于2017年6月发布。

Object.values/Object.entries

在ES8 /ES2017之前,Javascript开发者需要迭代一个对象的自身属性时候不得不用Object.keys,通过迭代且使用obj[key]获取value值返回一个数组。

let obj = {a: 1, b: 2, c: 3}
Object.keys(obj).forEach((key, index)=>{
console.log(key, obj[key])
})


而在ES6/ES2015中,使用for/of会稍微好点。

let obj = {a: 1, b: 2, c: 3}
for (let key of Object.keys(obj)) {
console.log(key, obj[key])
}


虽然使用老方式for/in也许会非常好用,但是当它碰到迭代枚举属性时,会破坏像prototype和tostring的属性得到意想不到的值。在ES8版本中,JordanHarband提出的Object.entries引入了一个entry概念。对象是键值对的数据结构,每个键值对都是entry。Object.entries(x)强制转换x为对象,并以数组的方式返回其可枚举的自定义字符串。例如:

>>Object.entries({foo:1,bar:2})
[['foo',1],['bar',2]]


与Object.entries非常相似,Object.values返回一个数组,其值为可枚举的字符串键值属性。

>> Object.values({foo:1,bar:2})
[1,2]


Object.entries( )和Object.values( )输出结果如下:

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


字符串填充

String.prototype.padStart 和 String.prototype.padEnd在javascript字符操作是一个不错的体验,引入padStart 和 padEnd,可以使开发人员更好地控制字符串原语。

padStart()在开始部位填充,返回一个给出长度的字符串,填充物给定字符串,把字符串填充到期望的长度。一个经典例子是使用空格创建列,使用它,可以帮助我们格式化一些字符串。

console.log('react'.padStart(10).length)         // "       react" is 10
console.log('backbone'.padStart(10).length)         // "  backbone" is 10


padEnd顾名思义就是从字符串的尾端右边开始填充。例如:

console.log('react'.padEnd(10, ':-)'))  // "react:-):-" is 10
console.log('backbone'.padEnd(10, '*')) // "backbone**" is 10


Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptors返回对象obj所有自身属性描述。这是一个多参数版本的Object.getOwnPropertyDescriptors(obj,propName)将会返回obj中propName属性的一个单独描述。

在ES5中,ECMAScript中没有单个方法来简化两个对象之间的正确拷贝。开发者要使用Object.assign()来拷贝对象, Object.assign()分配属性只有copy和定义新的属性。当我们使用更加复杂对象和类原型,这可能会出问题。

Object.getOwnPropertyDescriptors允许创建真实的对象浅副本并创建子类,它通过给开发者描述符来做到这一点.在Object.create(prototype, object)放入描述符后,返回一个真正的浅拷贝。

Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
)


异步函数

异步函数(或者async/await)特性操作是Promise最重要的功能。使用Promises处理Async函数的一种普遍写法如下所示:

function fetchData(url) {
return fetch(url)
.then(request => request.text())
.then(text => {
return JSON.parse(text);
})
.catch(err => {
console.log(`Error: ${err.stack}`);
});
}


在ES8中,新增async和await关键字,我们可以利用它来实现同步读取操作。在内部,Async功能与生成器的功能相同,但是却不能转换为Generator Functions。使用ES2017中的Async函数如下:

async function fetchData(url) {
try {
let request = await fetch(url);
let text = await request.text();
return JSON.parse(text);
}
catch (err) {
console.log(`Error: ${err.stack}`);
}
}


有了 async/await,我们的代码执行异步看起来像执行同步一样。可以从头到尾读起来非常简单和易懂,因为出现结果顺序和函数题中从头到尾顺序一样啊!

共享内存与原子操作

当内存被共享时,多个线程可以并发读、写内存中相同的数据。原子操作可以确保那些被读、写的值都是可预期的,即新的事务是在旧的事务结束之后启动的,旧的事务在结束之前并不会被中断。

Atomic 对象类似于 Math 对象,拥有许多静态方法,所以我们不能把它当做构造函数。 引入此功能后,低级别Atomics命名空间对象和一个SharedArrayBuffer构造函数,能够让开发人员开发共享多个service worker和核心线程之间的SharedArrayBuffer对象的数据,从而可以改善worker之间的协调。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: