JavaScript ES7/8/9 新特性

JavaScript ES7/8/9 新特性

ES7 新特性 (ECMAScript 2016)

ES7 在 ES6 的基础上主要添加了两项内容:

  • Array.prototype.includes() 方法
  • 求幂运算符(**)

Array.prototype.includes() 方法

includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。

 let arr = [1, 2, 3];
 console.log(arr.includes(3))
 // true
复制代码

includes() 接受第二个参数,数值型,表示从当前数组的第几个索引开始查找。

['a', 'b', 'c', 'd'].includes('b', 1) // true
['a', 'b', 'c', 'd'].includes('b', 2) // false
复制代码

对比 indexOf() 方法:

let arr = ['a', 'b', 'c', 'd', NaN]
console.log(arr.indexOf('c')); // 2
console.log(arr.indexOf('f')); // -1
console.log(arr.indexOf(NaN)); // -1
console.log(arr.includes(NaN)); // true

// 判断条件
if (arr.indexOf('b') !== -1) {
  console.log('数组存在 b');
}

if (arr.includes('b')) {
  console.log('数组存在 b');
}
复制代码

从上可以看出,若一个数组中存在 NaN, 则 indexOf() 无法判断,includes() 则可以。 if 条件判断的时候,includes() 也要简单一些。

求幂运算符(**)

ES7 中,使用 ** 来替代 Math.pow().

4 ** 3    // 64
复制代码

效果等同于:

Math.pow(4, 3)   // 64
复制代码

还支持一下写法:

let n = 4
n **= 3
console.log(n) // 64
复制代码

ES8 新特性 (ECMAScript 2017)

主要新功能:

  • 异步函数 Async Functions
  • 共享内存和Atomics(暂没研究)

次要新功能:

  • Object.values / Object.entries
  • String padding
  • Object.getOwnPropertyDescriptors() (没研究)
  • 函数参数列表和调用中的尾逗号

异步处理 - async / await

async 起什么作用

问题在于 async 是怎么处理返回值的, 写段代码测试一下,看看会返回什么。

async function testAsync() {
    return "hello world"
}
const result = testAsync()
console.log(result)
复制代码

结果表明 --- 输出的是一个 Promise 对象.

所以,async 函数返回的是一个 Promise 对象。async 函数(包含函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。

那么:

testAsync().then(v => {
  console.log(v);  // hello world
})
复制代码

猜想一下,如果 async 没有返回值,又该怎样呢? 则,它会返回 Promise.resolve(undefined)

await 是干什么的呢

一般来说,都认为 await 是在等待一个 async 函数完成。 我认为,因为 async 是返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数。

function getSomething () {
 return 'something'
}

async function testAsync () {
 return Promise.resolve("hello world")
}

async function test () {
 const v1 = await getSomething()
 const v2 = await testAsync()
 console.log(v1, v2);
}
test()
复制代码

awiat 是一个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。

如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。

如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

async / await 尝试

setTimeout 模拟耗时的异步操作,与 promise 比较;

  • promise 实现
function takeLongTime() {
    return new Promsie(resolve => {
        setTimeout(() => {
            resolve("hello world")
        }, 1500)
    })
}
takeLongTime.then(v => {
    console.log(v) // hello world
})
复制代码
  • async / await 实现
function takeLongTime() {
    return new Promsie(resolve => {
        setTimeout(() => {
            resolve("hello world")
        }, 1500)
    })
}
async function test() {
    const result = await takeLongTime()
    console.log(result)
}
test()
复制代码

这两段代码,两种方式对异步调用的处理(实际就是对 Promise 对象的处理)差别并不明显。下面测试 promise 含有多个 then 链的情况

async/await 处理 then 链

假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。我们仍然用 setTimeout 来模拟异步操作:

 // 处理多个 promise 组成的 then 链
/**
* 传入参数 n,表示这个函数执行的时间(毫秒)
* 执行的结果是 n + 200,这个值将用于下一步骤
*/

function takeLoneTime(n) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(n + 200)
    }, n)
  })
}

function step1(n) {
  console.log(`step1 with ${n}`)
  return takeLoneTime(n)
}

function step2(n) {
  console.log(`step2 with ${n}`)
  return takeLoneTime(n)
}

function step3(n) {
  console.log(`step3 with ${n}`)
  return takeLoneTime(n)
}
复制代码
  • promise 实现
function doIt() {
    console.time("doIt")
    const time1 = 500
    step1(time1).then(time2 => step2(time2))
                .then(time3 => step3(times))
                .then(result => {
                    console.log(result)
                    console.timeEnd("doIt")
                })
}
// step1 with 500
// step2 with 700
// step3 with 900
// result is 1100
// doIt: 2114.56689453125ms (500 + 700 + 900)
复制代码
  • async/await 实现
async function doIt() {
    console.time("doIt")
    const time1 = 500
    const time2 = await step1(time1)
    const time3 = await step2(time2)
    const result = await step3(time3)
    console.log(`result is ${result}`)
    console.timeEnd("doIt")
}

// step1 with 500
// step2 with 700
// step3 with 900
// result is 1100
// doIt: 2113.227783203125ms
复制代码

async/await 用法简洁了许多。

那么,现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。

function takeLoneTime(n) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(n + 200)
    }, n)
  })
}

function step1(n) {
  console.log(`step1 with ${n}`)
  return takeLoneTime(n)
}

function step2(m, n) {
  console.log(`step2 with ${m} and ${n}`)
  return takeLoneTime(m + n)
}

function step3(k, m, n) {
  console.log(`step3 with ${k}, ${m} and ${n}`)
  return takeLoneTime(k + m + n)
}
复制代码
  • async/await 实现
async function doIt() {
    console.time("doIt")
    const time1 = 500
    const time2 = await step1(time1)
    const time3 = await step2(time2, time1)
    const result = await step3(time3, time2, time1)
    console.timeEnd("doIt")
    console.log(`result is ${result}`)
}

// step1 with 300
// step2 with 500 and 300
// step3 with 1000, 500 and 300
// result is 2000
// doIt: 2908.927978515625ms  (300 + 800 + 1800)
复制代码
  • promise 实现
function doIt() {
    console.time("doIt")
    let time1 = 300, time2, time3
    step1(time1)
        .then(param => step2(time1, time2 = param))
        .then(param => step3(time1, time2, time3 = param))
        .then(param => console.log(`result is ${param}`))
        console.timeEnd("doIt")
}

// step1 with 300
// step2 with 300 and 500
// step3 with 300, 500 and 1000
// result is 2000
// doIt: 2917.6201171875ms   
复制代码

Object.values and Object.entries

ES5 中引入了 Object.keys() 方法,返回一个指定对象自己的所有的可遍历的属性的键名的 数组。

let obj = { a: 'aaa', b: 'bbb' }
console.log(Object.keys(obj)); // ["a", "b"]
复制代码
  • Object.values() 返回一个给定对象自己的所有可枚举的属性的 value 值的数组。对象自身可遍历
const obj = {  x: 'hello', y: 'world' }
console.log(Object.values(obj)) //  ["hello", "world"]

const arr = ['a', 'b', 'c']
console.log(Object.values(arr)) // ["a", "b", "c"]

// 如果键 是使用数字时,则返回的是数字排序
const obj = { 10: 'aaa', 1: 'bbb', 5: 'ccc' }
console.log(Object.values(obj)) // ["bbb", "ccc", "aaa"]

// 为字符串时,将每个字符切割成数组的每一项
console.log(Object.values('abc2'))  // ["a", "b", "c", "2"]
复制代码
  • Object.entries() 方法返回一个对象自身可遍历属性 [key, value] 的数组,排序规则与 Object.values() 一样。
const obj = {  x: 'hello', y: 'world' }
console.log(Object.entries(obj)) //  [[["x", "hello"]], ["y", "world"]]

const arr = ['a', 'b', 'c']
console.log(Object.entries(arr)) // [["0", "a"], ["1", "b"], ["2", "c"]]

// 如果键 是使用数字时,则返回的是数字排序
const obj = { 10: 'aaa', 1: 'bbb', 5: 'ccc' }
console.log(Object.entries(obj)) // [["1", "bbb"], ["5", "ccc"], ["10", "aaa"]]

// 为字符串时,将每个字符切割成数组的每一项
console.log(Object.entries('abc2'))  // [["0", "a"], ["1", "b"], ["2", "c"], ["3", "2"]]


// 基本用途:遍历对象的属性
const obj = { one: 1, two: 2}
for (let [k, v] of Object.entries(obj)) {
  console.log([k, v]);
  // ["one", 1]
  // ["two", 2]
}
复制代码

String - padStart / padEnd

String 对象增加的 2 个函数, 作用是填补字符串的首部和尾部。

str.padStart(targetLength, padString)
str.padEnd(targetLength, padString)

第一个参数 targetLength (目标长度), 想要的结果字符串的长度。 第二个参数 padString 是可选的,用于填充到源子符串。 默认是 空格

结尾逗号

代码展示:

// 参数定义时
function foo(
    param1,
    param2,
) {}

// 函数调用时
foo(
    'abc',
    'def',
);

// 对象中
let obj = {
    first: 'Jane',
    last: 'Doe',
};

// 数组中
let arr = [
    'red',
    'green',
    'blue',
];
复制代码

改动的好处呢?

  • 操作最后一项的数据时,不必添加或删除逗号;
  • 它可以帮助版本控制系统跟踪实际发生的变化。(网上查阅,不是很明白)

ES9 新特性 (ECMAScript 2018)

主要新功能:

  • 异步迭代
  • Rest/Spread 属性

新的正则表达式:

  • RegExp named capture groups
  • RegExp Unicode Property Escapes
  • RegExp Lookbehind Assertions
  • s (dotAll) flag for regular expressions

其他新功能:

  • Promise.prototype.finally()
  • 模板字符串修改

rest / spread 属性

ES6 中已经引入 rest 参数和扩展运算符,但是仅限于数组:

// rest参数 p3 为一个数组
function restParam(p1, p2, ...p3) {
    console.log(p1, p2, p3);  
 }
 restParam(1, 2, 3, 4, 5)  // 1   2   [3, 4, 5]
 
 
// 扩展运算符: 将一个数组转为用逗号隔开的参数序列
 const arr = [99, 100, -3, 45, 10]
 console.log(Math.max(...arr)); // 100
复制代码

ES9 中,为对象提供了像数组一样的 rest 参数和扩展运算符

const obj = {
   a: 1,
   b: 2,
   c: 3,
 }
 const { a, ...param } = obj
 console.log(a); // 1
 console.log(param); // { b: 2, c: 3 }
 
 function foo({a, ...param}) {
   console.log(a);
   console.log(param);
 }
 foo(obj) 
 // 1
 // { b: 2, c: 3 }
 
 // 合并对象
const a = {one: 1, two: 2 }
const b= {three: 3}
const ab = { ...a, ...b }
console.log(ab);  // {one: 1, two: 2, three: 3}
// 等价于 =》 
console.log(Object.assign(a, b))
复制代码

Promise.prototype.finally()

promise
  .then(result => {···})
  .catch(error => {···})
  .finally(() => {···});
复制代码

转载于:https://juejin.im/post/5c19c8105188251920597c0d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值