前言
ES2015-ES2020(ES6-ES12)新特性,还在只关注ES6么,ES6是2015年推出,现在都2021年底了,你知道ES这五年是怎么过的么,你造么?
本文我替ES讲讲它的故事
ES6(2015)
ES6 我按照 两个分类来方便大家记忆:
1. 使javaScrip更健壮的特性
2. 提升开发体验的语法糖
使javaScrip更健壮的特性
1. 类(class)
用来属性和方法的集合,class 的写法 有构造函数,
可设置静态方法、类的继承(extend)、super() 来调用父类。
2. 模块化(exprot、improt)
导出可以设置默认导出、可导出多个
扩展:import defaultExprot, {XXX,XXX} from 'XXX' 这样可以同时导入默认模块的和具名模块
3. Map、Set
Map: key、value 键值对来设置
方法:有set(kay,value),has(kay),size,delete(key),entrise()
遍历: foreach、of
特点:map 和 object 的不同 map key 可以不用字符串
Set: 类似数组 但是元素没有重复值
方法:有add(value),has(value),size,delete(value),clear()
kes(),values(),
遍历: foreach、of
特点:元素不可重复、可用于数组去重
扩展:通过Array.from() 将set转换为数组
其他:
WeakMap:存放的key不能是基本类型,不可遍历,没有size属性
WeakSet: 存放的元素不能是基本类型,不可遍历,没有size属性
4. let、const
let 类型不提升、const 常量
思考: const 如何使对象内部的值也不被改变
5. promise
实例的方法:
.then(), .catch(), finally()
原型的方法:
.all([p1,p2,p3]) // 有一个失败全都失败
.race([p1,p2,p3]) // 有一个率先改变状态就率先改变状态
.allSettled([p1,p2,p3]) // 等所有的都返回结果、无论成功还是失败
.resolve()
.reject()
6. Symbol()
独一无二的值,一般用于对象的key, 防止相同名称会报错
7. 对象新增方法
Object.is() // 类似于 == 判断,但和== 不同的是 NaN == NaN 是 true
Object.assign({},{}) // 对象合并、是浅拷贝
其他:Object.values()、Object.keys()、Object.entrise()
提升开发体验的语法糖
1. 箭头函数
()=> {} , 注意:this指向问题
2. 解构赋值
数组的解构赋值、对象的解构赋值 (可设置默认值、可解构字符串)
举例:
const [a,b,c,d = 40] = [10,20,30]
const [a,,c] = [10,20,30]
const {a,b,c} = {a: 10, b:20, c:30}
const {a,c} = {a: 10, b:20, c:30}
const {a,b,c} = 'string'
3. 扩展操作符(...)
(...) 展开数组、展开对象、展开字符串
举例:
let arrClone = [...arr]
let objClone = { ...obj }
let strArr = [...'hello']
4. 函数参数默认值
function myFunc (name='gby', age='60') {...}
5. 模板字符串(``)
模板字符串中${ } 不仅可以放变量 还可以进行
`你好${name}` , `${a}乘以${b}等于${a*b}`
以下这几年的更新我觉得按年份来记比较好记ES2016-ES2020,按版本不太好记忆
ES7(2016)
1. Array.prototype.includes()
// 判断数组是否存在某个元素
let arr = [10, 20 ,30]
以前是arr.indexOf(10) > -1 这样判断, 现在可以
arr.includes(10) // true 、 false
2. 求幂运算符
举例:
a的三次方
a**=3 或者 a = a**3
ES8(2017)
1. Object.values / Object.entries
获取所有值、获取所有的键值对,返回的是数组
2. 字符串的填充(String padding)
'XXX'.padStart('长度',, 元素)
'XXX'.padEnd('长度', 元素)
扩展:
trimStart/ trimEnd 去除首/尾空格
3. 函数参数列表和调用中的尾逗号
// 有些情况下我们的参数需要换行写就会像下面这种:
function setObj(
name,
age
) {.....}
// 如上代码另一个人继续追加代码的时候,git提交的时候就会有如下情况:
function setObj(
name,
age, // 这行是你的修改
sex, // 这行是你的新增
){ ..... }
就因为多加个逗号这样在git中这两行都显示是你的提交了,这样会引起不必要的甩锅事件
// 现在可以这么写了, 以逗号结尾,不会影响参数的length
function setObj(
name,
age, // 支持逗号结尾
) { ..... }
4. Object.getOwnPropertyDescriptors
见名知意:获取自己的属性描述符
语法: Object.getOwnPropertyDescriptor(obj, prop)
举例:
o = { bar: 42 };
d = Object.getOwnPropertyDescriptor(o, "bar");
// d {
// configurable: true,
// enumerable: true,
// value: 42,
// writable: true
// }
5. async/await
async 定义异步函数
await 执行同步等待
项目中都会经常用到的,如果没用过可以尝试试一下哦,
解决了回调地狱问题,会使我们的代码更简洁,更直观
并且比 * yield 这种方式更语义化
ES9(2018)
Promise.prototype.finally
无论成功与否都会执行,一般于关闭loading或者打开其他定义的事件.
p.finally(function() {
// 返回状态为(resolved 或 rejected)
});
扩展:
try 也有 finally
try {...} finally {...}
异步迭代
1. for-await-of
for await (const line of readLines(filePath)) {
console.log(line);
}
2. while await
async function* readLines(path) {
let file = await fileOpen(path);
try {
while (!file.EOF) {
yield await file.readLine();
}
} finally {
await file.close();
}
}
扩展:forEach下执行异步等待是没效果的
ES10(2019)
可选catch绑定
// catch 是一个函数的形式(带括号)
try {
// try to use a web feature which may not be implemented
} catch (unused) {
// fall back to a less desirable web feature with broader support
}
// 允许catch省略绑定及其周围的括号(不带括号)
try {
//
} catch {
//
}
Object.fromEntries
将entries格式的元素转换成对象。
obj = Object.fromEntries([['a', 0], ['b', 1]]); // { a: 0, b: 1 }
map = new Map([ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]);
obj = Object.fromEntries(map);
trimStart / trimEnd
str.trimEnd(); // 去除尾空格
str.trimStart(); // 去除首空格
Array.prototype.{flat,flatMap}
听说过数组扁平化么?
将 [[1,[2,3]],[[4,5],6],[7,8,9]] 转化为 [1,2,3,4,5,6,7,8,9]
也就是将多维矩阵转成一维数组
举例:
let arr1=[1,2,['a','b','c',['e','f']],3];
arr1.flat() // [1, 2, 'a', 'b', 'c', ['e','f'], 3]
arr1.flat(3) // [1, 2, 'a', 'b', 'c', 'e', 'f', 3]
arr1.flat(Infinity) //[1, 2, 'a', 'b', 'c', 'e', 'f', 3]
flat默认相当于2, 传递的数字就是按几维格式展开
flatMap()方法对原数组的每个成员执行一个函数(相当于执行`Array.prototype.map()`),
然后对返回值组成的数组执行`flat()`方法。该方法返回一个新数组,不改变原数组。
[2,3,4].flatMap((x)=>[x, x *2]) // [2, 4, 3, 6, 4, 8] // 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[1,2,3,4].flatMap(x =>[[x *2]])// [[2], [4], [6], [8]]// 相当于 [[[2]], [[4]], [6]], [6]], [8]]].flat()
ES11(2020)
动态import
标准用法的import导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。
请不要滥用动态导入(只有在必要情况下采用)。静态框架能更好的初始化依赖,而且更有利于静态分析工具和tree shaking发挥作用
关键字import可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 `promise`。
import('/modules/my-module.js')
.then((module) => {
// Do something with the module.
});
这种使用方式也支持 `await` 关键字。
let module = await import('/modules/my-module.js');
BigInt
新增基本类型 BigInt, 用于对超大数进行运算
创建 bigint 的方式有两种:在一个整数字面量后面加 n 或者调用 BigInt 函数,该函数从字符串、数字等中生成 bigint。
const bigint = 9007199254740991
const sameBigint = BigInt("9007199254740991");
const bigintFromNumber = BigInt(10); // 与 10n 相同
更多详情可见MDN BigInt
扩展:其他基本类型
Promise.allSettled
allSettled // 都稳定下来
都状态更改无论成功或是失败时才算完成
空合并运算符
就是短路或。
const response = {
settings: {
nullValue: null,
height: 400,
animationDuration: 0,
headerText: '',
showSplashScreen: false
}
};
const undefinedValue = response.settings.undefinedValue || 'some other default'; // result: 'some other default'
const nullValue = response.settings.nullValue || 'some other default'; // result: 'some other default'
ES12(2021)
String.prototype.replaceAll
以前使用替换的时候, 如果想要全局替换需要用正则 /g 进行全部的替换,是不是麻烦,现在js也可以使用replaceAll了。
'1+2+3+4'.replace(/\+/g, '-') // '1-2-3-4'
replaceAll:
'1+2+3+4'.replaceAll('+', '-') // '1-2-3-4'
可选链调用
let street = user.address?.street
// 当 user.address 存在的时候再去找street这样避免没有address时在继续获取street会报错的情况
let fooValue = myForm.querySelector('input[name=foo]')?.value
// 同理
Promise.any
- 只要其中的一个
promise成功,就返回那个已经成功的promise - 如果可迭代对象中没有一个
promise成功(即所有的promises都失败/拒绝),就返回一个失败的 - 目前是实验性的,不推荐使用