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方法默认挂载在数组原型上。
拥有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.padStart 和String.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和示例4len < 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
// }
// }