前言
我这里为啥子叫 重学,实在是因为在业务代码中还是会经常看到ES5的影子,也不是说用ES5写法不行,只是会有BUG,造成代码量增多,可读性变差而已。
偏偏,有一丢丢代码洁癖,经验呢说长不算长,说短也不短,3-5年经验的同学,着实不想面对这样的代码,重新学习并整理一下ES6新特性,巩固自己,帮助别人,快乐你我他~
ES6+的由来
ES6是ECMA为JavaScript指定的第6个标准版本,标准委员会最终决定,标准在每年6月正式发布并作为当年的正式版本,接下来的时间里就在此版本的基础上进行改动,直到下一年6月草案就自然变成新一年的版本,这样一来就无需以前的版本号,只要用年份标记即可。
ECMAscript 2015是在2015年6月发布ES6的第一个版本。以此类推,ECMAscript 2016是ES6的第二个版本、 ECMAscript 2017是ES6的第三个版本。ES6 既是一个历史名词也是一个泛指,含义是5.1版本以后的JavaScript下一代标准,目前涵盖了ES2015、ES2016、ES2017、ES2018、ES2019、ES2020。
所以市面上提到的 ES7、ES8、ES9、ES10、ES11等,实质上都是不规范的概念,从ES1到ES6,每个标准都是花了好几年甚至十多年才制定下来,你一个ES6到ES7,ES7到ES8,才用了一年,按照这样的定义下去,那不是很快就ES20了。用正确的概念来说ES6目前涵盖了ES2015、ES2016、ES2017、ES2018、ES2019、ES2020。在这里姑且把这些叫作 ES6+ 吧。
正文
1. let / const
let和const是声明变量和常量的命令,在ES5中我们可以使用var来声明,那么为什么会出现let、const,而不继续使用var,他们之间有什么区别呢?
- 具体区分变量与常量:let声明变量,const声明常量
- 作用域不同:let和const在代码块中执行,var在全局代码中执行
- 不可进行重复定义:let和const不允许重复声明,var可重复声明
- 不存在变量提升:let和const若未定义变量进行使用就会报错,var存在变量提升
2. 解构赋值
-
对象解构
const { name, age, height } = { name: 'wendy', age: 18, height: 167 }; console.log(name, age, height); // 'wendy', 18, 167 // 设置默认值 const { name = 'wendy', age, height } = { age: 18, height: 167 }; // 改变变量名 const { name, age, height: h } = { name: 'wendy', age: 18, height: 167 }; -
数组解构
const arr = [1, 2, 3]; const [a, b, c] = arr; console.log(a, b, c); // 1,2,3 const [, , d] = arr; console.log(d); // 3 const [e, ...rest] = arr; console.log(e, rest); // 1, [2, 3]
注:
- 只要等号两边的模式相同,左边的变量就会被赋予对应的值
- 只要等号右边的值不是对象或者数组,就将其转化为对象
- 解构不成功时,变量的值等于
undefined undefined和null无法转为对象,因此无法进行解构
3. 字符串模板
就是用 `` 将字符串包裹起来。
可以对字符串进行换行和插值,写法上更流畅、简洁。
在${}中可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
// 换行
const str = `wen
dy`;
// 插值
const age = 18;
const str = `wendy: ${age}岁`;
console.log(str); // 'wendy: 18岁'
请摒弃以下写法
const age = 18;
const str = 'wendy: ' + age + '岁';
4. 字符串扩展
-
字符串遍历:通过for-of遍历字符串
-
字符串模板
-
repeat():把字符串重复 n 次,并返回 新的字符串
-
Includes():是否存在指定字符串
-
startsWith():是否存在字符串头部指定字符串
-
endsWith():是否存在字符串尾部指定字符串
const str = 'wendy'; console.log(str.includes('d')); // true console.log(str.startsWith('w')); // true console.log(str.endsWith('n')); // false
5. 数值扩展
- Number.parseInt():返回转换值的整数部分
- Number.parseFloat():返回转换值的浮点数部分
- Number.isNaN():是否为NAN
- Number.isInteger():是否为整数
- Math.trunc():返回数值整数部分
- Math.sign():返回数值类型(整数 1、负数 -1、零 0)
6. 对象扩展
- 属性名表达式:字面量定义对象时使用
[]定义键[key] - Object.assign():合并对象(浅拷贝),返回原对象
- Object.getPrototypeOf():获取对象的原型对象
- Object.setPrototypeOf():设置对象的原型对象
- 遍历对象:
for-in遍历对象自身可继承可枚举属性 - Object.keys:返回对象属性键组成的数组
- Object.is():比较俩值是否相等
- Object.hasOwnProperty():判断对象是否含有指定属性,返回布尔值
7. 数组扩展
- 扩展运算符(...):转换数组为用逗号分隔的参数序列([...arr])
- Array.from():转换数组,返回新数组
- Array.of():转换一组值为真正数组,返回新数组
- find():返回第一个符合条件的成员
- findIndex():返回第一个符合条件的成员索引值
- fill():根据指定值填充整个数组,返回原数组
8. 函数扩展
-
给函数形参设置默认值
// 带默认参数的形参一般放在后面,减少传参导致的错误几率 function func (name, age = 18) { // TODO: do something }; -
使用
...rest形式设置剩余形参,支持无限参数(替换arguments对象)// 剩余参数,转化成数组 const restParams = function(...args) { console.log(args.toString()); // 1, 2, 3, 4, 5 } restParams(1, 2, 3, 4, 5);
9. 箭头函数
- 简化了函数的写法
- 无参数:() => {}
- 单个参数:x => {}
- 多个参数:(x, y) => {}
- 解构参数:({x, y}) => {}
- 没有this机制,this指向固定化,有利于封装回调函数
10. Promise
- 概念:包含异步操作结果的对象
- 状态:
- 进行中:pending
- 已成功:resolved
- 已失败:rejected
- 作用:
- 对象的状态不受外界影响
- 解决异步编程中回调嵌套过深的问题
- 声明:new Promise((resolve, reject) => {})
- 方法:
- then():
resolved状态和rejected状态的回调函数 - catch():异常回调
- Promise.all():将多个实例包装成一个新实例,返回全部实例状态变更后的结果数组
- Promise.race():将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果
- then():
11. Async / Await
-
概念:async函数就是Generator函数的语法糖,async函数的await命令后面 可以是promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
-
async 函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是内部then命令的语法糖。
-
实例:
// 指定时间返回数据 function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('wendy', 6000);
12. Module
-
指令:
- export:导出模块对外接口
- 默认导出:export default Person (导入时可指定模块任意名称,无需知晓内部真实名称)
- 单独导出:export const fetchName = "wendy"
- 按需导出:export { fetchName, fetchAge }(推荐使用)
- 改名导出:export { fetchName as getName }
- import:导入模块内部功能
- 默认导入:import Common from "common"
- 整体导入:import * as Common from "common"
- 按需导入:import { fetchName, fetchAge } from "common"
- 自执导入:import "common"
- 复合导入:import Common, { fetchName } from "common"
注:
- 一个模块就是一个独立的文件,该文件内部的所有变量,外部无法获取
import命令大括号里的变量名必须与被导入模块对外接口的名称相同
- export:导出模块对外接口
13. Set
-
概念:一种类似于数组的数据结构,成员值都是唯一且没有重复的值
-
声明:const set = new Set(arr)
-
特点:
- 元素唯一性,不允许重复元素
- 使用 add 添加重复元素,将会被忽略
-
方法:
- add():添加值,返回实例
- delete():删除值,返回布尔值
- has():检查值,返回布尔值
- clear():清除所有成员
- keys():返回以属性值为遍历器的对象
- values():返回以属性值为遍历器的对象
- entries():返回以属性值和属性值为遍历器的对象
- forEach():使用回调函数遍历每个成员
-
用途:
-
数组去重
-
数据存储
const arr = [1, 2, 3, 2, 2]; const set = new Set(arr); set.add(1).add(1); console.log(set.size); // 3 const newArr = Array.from(set); console.log(newArr); // [ 1, 2, 3 ]
-
14. Map
-
概念:一种类似于对象的数据结构,以 key、value形式存储数据
-
声明:const map = new Map(obj)
-
其他与 set 无什么差别
-
实例:
const map = new Map(); map.set('name', 'wendy'); map.forEach((val, key) => {console.log(key, val)});
15. Generator
-
概念:封装多个内部状态的异步变成解决方案
-
声明:function* func() {},一般配合 yield 关键字使用
-
方法:next() 让函数恢复执行且使用不同的语句替换 yield 命令
-
特性:
- 惰性执行,调 next 才会往下执行
- 解决异步回调过深的问题
-
实例:
function* crateIdGenerator() { let id = 1; while(id < 3) yield id++; } const createId = crateIdGenerator(); const createId = createIdGenerator(); console.log(createId.next()); // { value: 1, done: false } console.log(createId.next()); // { value: 2, done: false } console.log(createId.next()); // { value: undefined, done: true }
总结
巴啦啦了一大堆,啥时候用就啥时候来看吧,每个人都在说使用ES6,你倒是用啊,哈哈哈~
emmmm,开玩笑的啦,还是希望能真正了解为什么要使用ES6+吧,努力写出更流畅、更规范、更健壮的代码!