ES6、ES7、ES8

171 阅读6分钟

ECMAScript版本对比

ECMAScript版本发布时间新增特性
ECMAScript 2009(ES5)2009年11月扩展了Object、Array、Function等功能
ECMAScript 2015(ES6)2015年6月类、模块化、箭头函数、函数参数默认值等
ECMAScript 2016(ES7)2016年3月includes,指数操作符
ECMAScript 2017(ES8)2017年6月async/await,Object.values(), Object,entries(), String padding等

ES6

ES6中的特性比较多,在ES5发布近6年后才将其标准化,两个发布版本之间时间跨度很大,所以ES6中的特性比较多。 在这里列举几个常用的

  • 模块化
  • 箭头函数
  • 模版字符串
  • 解构赋值
  • 延展操作符
  • 对象属性简写
  • Promise
  • let与const

iterator迭代器

iterator迭代器是ES6非常重要的概念,是另外4个ES6常用特性的实现基础(解构赋值,扩展运算符,生成器,for of循环),另外ES6种的Map,Set数据也有使用它。
对于可迭代的数据,ES6内部部署了一个[Symbol.iterator]属性,他是一个函数,执行后会返回iterator对象(也叫迭代器对象),而生成iterator对象[Symbol.iterator]属性iterator接口。
数组上的Symbol.iterator方法默认挂载在数组原型上。 image.png

拥有iterator的数据类型:

  • Array
  • Map
  • Set
  • String
  • 类数组
  • agruments对象
  • NodeList对象

iterator迭代器对象,具有next方法

let arr = [1, 2, 3];
let iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
console.log(iterator.next()); // {value: undefined, done: true}

for … of循环

for of是ES6中新增的遍历方式,允许便利一个含有iterator接口的数据并且返回各项的值,和 ES3中 for in区别,可参考文章for in 和 for of
for of循环的原理其实也是利用了可迭代对象内部部署的iterator接口,如果把for of循环拆分为原始的for循环,可以理解为

let arr = [1, 2, 3, 4, 5];
let iterator = arr[Symbol.iterator]();
for(let res = iterator.next(); !res.done; res = iterator.next()) {
    let value = res.value;
    console.log(value);
}
// 1 2 3 4 5

函数默认值

基础使用

// es5
function foo5(agr1) {
    const arg = arg1 || 1;
    // do something
}

function foo6(arg = 1) {
    // do something
}

当前上面两种写法的效果不是完全等同的,当传入的参数的值 为undefined 、0、 null、空字符串 或者其他转化为boolean类型值为false的参数时,这两者是有区别的。

作用域问题

如果使用了函数默认参数,在函数的参数的区域(括号里面),会作为一个单独块级作用域,并且拥有let/const方法的一些特性。

默认参数的复制操作,在函数调用时执行,比如下面的代码,如果不调用,是不会报错的,如果调用就会报错,因为z在初始化前使用了。

const w = 1, z = 2;
function foo(x = w + 1, y = x + 2, z = z + 1) {
    console.log(x, y, z)
    // do something
}
foo(); 
// Cannot access 'z' before initialization

模块化

// 导出 test.js
export {name: 'bajiu', age: 25}
export function foo(arg) {
    // do something
}

// 导入 use.js
import {name, age, foo} from './test.js'

延展操作符(Spread operator)

延展操作符…可以在函数调用/数据构造时,将数组表达式或者string在语法层面展开;
在ECMAScript 2018中延展操作符增加了对对象的支持

function sum(x, y, z) {
    return x + y + z;
}
const numbers = [1, 2, 3];
// 不使用延展操作符号
sum.apply(null, numbers);

// ES6
sum(...numbers);

ES7的特性

在ES6之后,ES发布的频率更加的频繁,基本每年一次,每个新版本的特性数量就比较少。

  • includes
  • 指数操作符

Array.prototype.includes

includes函数是用来判断数组是否包含某一个指定的值,如果包含就返回true,否则返回false

arr.includes(x);
arr.indexOf(x) > -1;

上面两个判断是等价的,都判断了数组arr中是否包含x

指数操作符

指数操作符**, 它具有与Math.pow()等效的计算结果。

console.log(Math.pow(2, 10)); // 1024
console.log(2 ** 10); // 1024

ES8的特性

  • async/await
  • Object.values()
  • Object.entries()
  • String padding
  • 函数参数列表结尾允许逗号
  • Object.getPropertyDescriptor()

async/await

拥有async标识的函数,如下charCountAdd返回的是一个Promise对象,可以继续用then进行链式调用,then回调函数的如参值是 return的值。如果没有返回值,那回调接收到的值就是undefined

function charCount(str) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(str.length);
        }, 500);
    })
}
async function charCountAdd(str1, str2) {
    const [l1, l2] = await Promise.all([charCount(str1), charCount(str2)]);
    console.log(l1, l2); // 5 2
    return l1 + l2
}
const total = charCountAdd('Hello', 'Hi').then(res => {
    console.log(total); // Promise {<pending>}
    console.log(res); // 7
});

const total1 = charCountAdd('Hello', 'Hi'); 
// 代码执行完成后,total的值是Promise {<fulfilled>: 7}

// 实例2
async function charCountAdd2(str1, str2) {
    const [l1, l2] = await Promise.all([charCount(str1), charCount(str2)]);
    console.log(l1, l2); // 5 2
}
const total2 = charCountAdd2('Hello', 'Hi').then(res => {
    console.log(total); // Promise {<pending>}
    console.log(res); // undefined
});

捕获异常

// 第一种:捕获整体的的错误
strTotalLen('Hello', 'Hi')
    .then(console.log)
    .catch(console.log)
    
// 第二种:捕获单个的await的错误
async function charCountAdd(str1, str2) {
    const l1 = await charCount(str1)
        .catch(e => console.log('str1 is error'));
    const l2 = await charCount(str2)
        .catch(e => console.log('str2 is error'));
    return l1 + l2;
}

// 第三种:利用try catch捕获执行中的错误
async function charCountAdd(str1, str1) { 
    let l1,l2;
    try { 
        d1=await charCount(data1);
        d2=await charCount(data2);
    }
    catch (e) {
        console.log('param is error');
    }
    return d1+d2;
}

Object.values()

对象的构成为键值对,我们熟悉的Object.keys函数可以返回一个对象键的集合,Object.values函数可以返回对象值的集合。两者都会忽略为Symbol类型的属性,如下面的Symbol(1)Symbol(2)

const obj = {
    name: 'bajiu',
    say: function() {
        console.log(`I'm` + this.name);
    },
    age: 24,
    [Symbol(1)]: Symbol(1),
    [Symbol(2)]: 2,
    3: Symbol(3)
}
console.log(Object.keys(obj)); // ['3', 'name', 'say', 'age']
console.log(Object.values(obj)); // [Symbol(3), 'bajiu', ƒ, 24]

Object.entries

函数返回一个对象自身可枚举属性的键值对的数组

const obj = {
    name: 'bajiu',
    say: function() {
        console.log(`I'm` + this.name);
    },
    age: 24,
    [Symbol(1)]: Symbol(1),
    [Symbol(2)]: 2,
    3: Symbol(3)
}
Object.entries(obj);
// [['3', Symbol(3)], ['name', 'bajiu'], ['say', ƒ], ['age', 24]]

String padding

新增了两个实例函数String.prototype.padStartString.prototype.padEnd,允许将字符串添加到原始字符串的开头或结尾。

console.log('baijiu'.padStart(9, 'Hi ')); // Hi baijiu
console.log('baijiu'.padStart(8, 'Hi ')); // Hibaijiu
console.log('baijiu'.padEnd(12, ' happy')); // baijiu happy
console.log('baijiu'.padEnd(10, ' happy')); // baijiu hap
console.log('baijiu'.padEnd(5)); // baijiu

baijiu表示原始字符串(str1)的值,9表示最终处理后字符串的长度(len),Hi 表示需要填充的字符串(str2)。

  • len > str1.length + str.length时,会以空格填充剩余长度
  • len >= str.length && len <= str1.length + str.length,会对str2进行截断操作,如上面的示例2和示例4
  • len < str.length时,不会进行任何操作,如示例5

Object.getOwnPropertyDescriptors()

获取一个对象所有自身属性的描述符,如果是空对象,则返回空对象

const obj = {
    name: 'bajiu',
    say() {
        return `hello $(this.name)`
    }
};
Object.getOwnPropertyDescriptors(obj);

// {
//    "name": {
//        "value": "bajiu",
//        "writable": true,
//        "enumerable": true,
//        "configurable": true
//    },
//    "say": {
//        "writable": true,
//        "enumerable": true,
//        "configurable": true
//    }
// }

资料

  1. 近一万字的ES6语法知识点补充
  2. ES6、ES7、ES8特性一锅炖(ES6、ES7、ES8学习指南)