共计 6131 个字符,预计需要花费 16 分钟才能阅读完成。
结合工作中使用情况,简单对 es6 进行一些复习总结,包括常用的语法,api 等,以及短时间内要上手需要重点学习的知识点(不同工作环境可能有一些差别),主要参考链接是阮一峰的博客以及外文博客(阮老师大部分文章是直接翻译的这个博客)http://2ality.com/p/about.html
1. 简介
先说一下 ECMAScript,ECMA 是一个标准化组织,他们制定了 JavaScript 的语言标准,所以之后一直称为 ECMAScript,广泛的讲,Javascript 是其一种标准实现,包括 ECMAScript,dom,bom 等
ECMA 组织每年都会有新标准发布,标准名为 ES+ 年份,所以我们会听到 ES2015,ES2016,ES2017 等,ES6 其实就是 ES2015,表示在 15 年发布的最新版本,相应的 ES2016,ES2017 分别称为 ES7 和 ES8,依次往后对应。
现在大部分博客,文章,分享中提到的 ES6 其实也可以理解为 ES6+,只不过因为 2015 年之前,ECMAScript 有很多年没有发版(也有历史原因:ES4 的夭折),积累了大量的新语法,api,所以在 2015 年一次性加在了 ES6 版本中发布,之后每年都只有很少的一些新增,比如:
- ES7: http://2ality.com/2016/01/ecm… (只有很少的两个属性)
- ES8:http://2ality.com/2016/02/ecm…
- …
语法提案
关于语法提案的流程,简单了解一下:一个新的语法从提案到成为标准需要经过五个阶段,每个阶段都需要标准委员会 TC39 定时开会进行批准
流程见链接:http://exploringjs.com/es2016…
需要注意的一点,所有的标准都是基于实现的,几大厂商浏览器对提案的实现必须先于标准才会进入定稿阶段,包括 Babel
我们常用的 async 和 await,就是因为 16 年开会的时候没有达到可定案的标准,而没有进入 ES2016 标准,最后添加在 2017 标准中
可参考该链接,有每年发布标准中新增的特性:http://2ality.com/2017/02/ecm…
2. 简单知识点介绍
下面主要就是结合平时工作,简单介绍最常用的语法,类方法以及实例方法等,下面主要是一些列举,大部分知识点想深入学习的话,还是得到阮老师博客或者外文博客上学习
不过我标注了实际工程中的使用频率,可以参考,针对性的学习,快速上手
提示:实际开发中结合 eslint 可以帮助自己写出更规范的代码
使用频率极高(为方便一起介绍,会将一些不常用的语法也列出来,标题括号中也为大量使用):
2.1 let 与 const
这是最基础的两个命令,都是声明变量,要强制所有的声明都使用他们两个
与 var 的区别:
-
作用域
- var 作用域在全局
- let 与 const 作用域为代码块
- 变量提升(https://www.jianshu.com/p/68a…)
- 暂时性死区,表示在一个块级作用域内,只要使用 let 声明一个变量,声明前将不能使用该变量
- 不允许重复声明
- 与顶层对象 window 或者 global 的关系,var 声明的全局变量与顶层变量挂钩,而 let const 声明的全局变量不挂钩
const 与 let 区别:
- const 定义一个只读的常量,一旦声明不可改变,但需要注意的是,不可改变的是变量指向的那个内存地址,如果使用 const 声明一个对象,对象内部是可以改变的,如果要强制一个对象不可改变,那么可以使用 Object.freeze 来冻结(该方法只冻结该对象,不会冻结其属性,所以可考虑递归)
2.2 默认值设置
我们可以直接在通过 param = 1 的形式设置默认值
包括为函数参数设置,为解构设置(见下面介绍)
避免了以前的这种写法:
function test(data) {data = data || {};
...
}
// 可以直接写为
function test(data = {}) {...}
需要注意的是:默认值生效的条件是,严格等于 undefined,如果值为 null,不会使用默认值
2.3 解构赋值与 rest 操作符
解构
解构赋值其实就是为了更方便的从数组或者对象中通过属性名取数据,熟练使用之后,配合默认值,rest 操作符可以很大程度提高效率,简化代码
下面是一些简单的使用对比
var a = 1, b = 2, c = 3;
// 或者
var param = {a: 1, b: 2, c: 3};
var a = param.a || 1; // 默认值
var b = param.b;
var c = param.c;
// 或者
function add(param) {param = param || {};
var v1 = param.v1 || 0;
var v2 = param.v2 || 0;
return v1 + v2;
}
可以看出来,如果参数比较多的话,代码很臃肿
如果用解构赋值,我们可以写成这样,很简洁
let [a, b, c] = [1, 2, 3]
// 或者
let {a = 1, b, c} = {a: 1, b: 2, c: 3}
// 或者
function add({v1 = 0, v2 = 0} = {}){return v1 + v2;}
// 类比上面代码,其中 {v1 = 0, v2 = 0} 这个对象接收 param 参数,如果 param 未传入,设置默认值为 {},进而,v1,v2 从 param 或者默认值{} 中取值,取不到的话也设置默认值
解构的核心是,= 号左边通过属性名直接获取 = 号右边对象相应的属性
并且所有类型的数据都可以被解构,即出现在 = 号右边,只不过字符串,数字,布尔值出现在等号右边时会先转化为对象
使用解构可以大大改善代码的可读性,减少的冗余的代码,更灵活简洁的获取属性,设置默认值,尤其是配合 rest 操作符时。
rest 操作符,即…
使用在函数参数中(取代 arguments)或者解构赋值时,方便我们批量的获取设置数据,大量用在数组和对象中,见下面 数组部分
该语法在 ES2018 中成为规范,但是工作中早已大量使用,参考博客 http://2ality.com/2016/10/res…
注意:… 只能出现一次并且必须出现在结尾
下面是错误的用法:
const {...rest, foo} = obj; // SyntaxError
const {foo, ...rest1, ...rest2} = obj; // SyntaxError
2.4 函数相关的扩展(箭头函数,rest 参数,默认值)
ES6 对函数进行了很多扩展,其中最常用的是箭头函数以及 rest 参数和默认值,rest 参数与默认值都与解构关系密切
2.4.1 默认值
- 一般在函数中设置默认值的参数应该是尾参数
- 如果指定了默认值,函数的 length 值为默认值参数前面未使用默认值的参数个数
注意:函数参数值会形成一个新的作用域,区别于函数内作用域
2.4.2 箭头函数
这个使用频率极高,大大简洁了代码,尤其作为回调传入的时候
与 es5 函数区别:
- 自动绑定函数定义时作用域 this,替换 bind 写法(在需要手动绑定 this 时,使用箭头函数)
- 不能作为构造函数
- 没有 arguments,使用 rest 代替
下面可选择性了解:
2.4.3 函数 name 属性,会返回函数名
- 可能用到的,使用 bind 绑定之后,name 属性前会加 bound 前缀
2.3.4 函数式编程中尾调用和尾递归,大大优化内存,待深入
2.5 字符串扩展(模板)
常用的主要是以下几点
最常用的是支持模板写法,使用反引号 “ 和 ${} 取代字符串拼接
// 比如:const a =‘222’, b =‘333’;
const c = a +‘444’+ b;
const c = `${a}444${b}`
剩下的选择性了解:
- 加强对 unicode 支持,使用频率很小
- 支持 for of 遍历,使用频率小,可使用 split 或者 rest 代替
- 增加搜索方法,includes,startsWith,endsWith,之前只有一个 indexOf
- repeat,padStart,padEnd 循环或者补全字符串,偶尔使用
2.6 数组扩展(rest 操作符,实例方法)
主要是增加以下常用点
-
…操作符,类 rest
- 替代 apply 写法,如下,还有很多比如 max,min 求值,push 一个数组等等
- 替代 concat
- clone
- 结合解构赋值等
- string -> array,替换 split 写法,并且可识别 4 字节的 unicode
- 将 iterator 接口的对象转化为数组,比如 dom 获取到的列表,任何部署了 Iterator 接口的类数组对象都可以,map,set 对象等
-
实例方法,比如 coryWithin,find,findIndex,fill,entries,keys,values,includes 等
- find,findIndex,includes 相比 indexOf,可以识别 NaN,并且更语义化
let a = [1, 2, 3], b = [2, 3, 4];
let merge = […a, …b] // [1, 2, 3, 2, 3, 4]
// 替换 apply
function func (a, b, c) {…}
// 如果需要传入一个数组,es5 就要这样写
func.apply(null, [1, 2, 3])
// es6
func(…[1, 2, 3])
// 反转字符串的实现
[…str].reverse().join(‘')
// 类数组对象
{‘0’:’12’,‘1’:‘123’,
length:‘2'
}
下面的选择性学习:
-
Array.form 将类数组对象或者实现了 iterator 接口对象转化为数组,常见的有 dom 集合,arguments,map,set 等,使用频率一般
- 区别于…操作符的是,不仅能转化 iterator,还能转化类数组对象,如上代码
- 可传入第二个参数,类似于 map 方法
- Array.of 将一组值转化为数组,替代 Array() 或者 new Array(),使用频率一般
2.7 对象扩展(遍历与简化写法)
简化对象写法,新增一些 Object 类方法,使用频率极高
主要更新
-
简化对象写法,工作中应该全面改写
- 比如{x, y} 等同于{x: x, y: y}
- 函数类似 {func() {}} 等同于 {func: function() {}}
- 新增 keys,values,entris 方法,获取对象的属性名数组,值数组或者键值对,使用较多,可配合 for of 使用(必须是可遍历对象)
- Object.is 类似于 ===,但是可识别 isNaN === isNaN // true 与 +0 === -0 // false,与我们主观意识一致
- Object.assign 合并对象的可枚举属性,后者会覆盖前者,属于浅拷贝
-
属性的遍历:
- for in 遍历自身以及继承的可枚举属性
- Object.keys 自身的可枚举属性键名
- getOwnPropertyNames 自身所有属性,包括不可枚举
- getOwnPropertySymbols 获取自身所有 symbol 属性键名,前三者都不包括 symbol
- Reflect.ownKeys 所有的自身属性
下面的选择性学习:
- 属性名可以用表达式
- 提供一些对原型链的操作,使用极少,有兴趣可研究
- 新增 super 字段,区别于 this,this 指向该对象,super 指向原型对象
3. 高级知识点
对上面使用频率高的知识点进行了解学习以后便可以进行基本开发了,熟练使用后自然会体会到 es6 的美
但是实际工作中,不可能都是这些基础语法,api,需要用到更多的高级知识点
目前我们在大量使用的有:
这儿做简单介绍,工作之余可以自己去深入,其中 Class 好理解,Module 和 Decorate 相对也好上手
主要是 Promise 与 Async,简单了解之后也可以快速写代码,但是当应用复杂时,还是需要你深入了解其工作原理
推荐首学 Promise,Decorator 可在用到时再学
3.1 Promise
这是重中之重,ES6 提出的异步的一种解决方案,要深入学习
3.2 async 与 await
也是异步的解决方案,代替 Generator,更友好,语义化的使用
3.3 Class
ES6 提供的语法糖,内部使用 prototype 实现,以面向对象的方式实现 JS
3.4 Decorate
装饰器,可以对类或者类方法进行装饰,增加一些额外的行为
3.5 Module
模块化的实现,帮助我们拆分组合代码,模块化开发
此处还有两个概念,CommonJS 和 AMD 模块
4. 使用频率低的一些特性:
除了前面介绍的,剩下就是一些工作中用到比较少的特性,包括一些你常用但是并不知道的底层技术,比如 Iterator,当你使用 … 或者 for of 时都会用到该知识点,建议学习
4.1 Set 与 Map
新增的数据结构,与 Java 中类似,目前来看,习惯未养成,使用比较少,但是建议学习
4.2 正则的扩展
工作中会常用的正则语法便可以了,推荐一个链接,帮助你更好的学习使用正则:https://regexper.com/#%2Fabc%…
有时候可以用先行断言和后行断言实现一些复杂的判断
- 字符串可使用正则的方法:match,replace,search,split,在 es6 环境下内部都是使用正则的方法来进行匹配,可以将 replace 第二个参数传入函数来观察函数参数,比如
- 新增 u 修饰符,可识别大于 uffff 的 unicode 字符
- 新增 y 修饰符,类似于 g,但是下次匹配必须从剩余字符串的头部开始,对应属性为 sticky
- 新增 flags 属性,返回修饰符
- 新增 dotAll 模式,见链接 http://2ality.com/2017/07/reg…,. 可以匹配任意单个字符,之前不匹配终止符,n r 等
- 支持后行断言,介绍见笔记本 -> 正则
- 新增具名组匹配,同上
- matchAll 一次性返回所有的匹配,返回结果是一个遍历器
4.3 symbol
es6 新增的原始数据类型,表示独一无二的值,一般使用为直接Symbol(str),Symbol.for(str),Symbol.keyFor(str)
现在有 string boolean,number,undefined,null,symbol 六种,JS 语言内部大量使用,工作中偶尔会用,比如定义私有属性的时候
const FETCH = Symbol('fetch');
import fetch from './lib/fetch';
module.exports = {get fetch() {if (!this[FETCH]) {this[FETCH] = fetch;
}
return this[FETCH;},
}
4.4 Proxy 与 Reflect,都是 JS 语言层次上的概念
Proxy 即在目标对象外设置一层代理,外界真正访问到该对象时必须先访问代理
Reflect 类似 Proxy,是 ES6 为了操作对象而新增的 Api,将一些 Object 上的对象放在了 Reflect 对象上,并修改了一些行为
4.5 数值方面的扩展
这部分主要是新增方法,使用频率总体不高
- 新增 0b 0o 表示二进制和八进制,es5 八进制表示为 0 开头(严格模式下不可用)
-
Number 新增类方法,
- isFinite 与 isNaN,与挂载在全局的两个方法区别是参数只能是数值,方法内部不会调用 Number()转化
- parseInt 与 parseFloat,与全局保持一致
- isInteger,参数只能为数值并且 25 与 25.0 一样,并且不在 js 精度范围内时会误判
- 常量 EPSILON,js 能够识别的最小误差
- Math 对象新增大量方法,很少用
- ** 指数运算,与 Math.pow 类似,对于特大运算,可能有误差