导图社区 JavaScript(ES6)核心知识总结
对JavaScript(ES6)的核心知识进行全面总结与梳理。
编辑于2021-08-09 22:09:52ES6核心知识总结
1.ECMAScript 6简介
ECMAScript 和 JavaScript 的关系
前者是后者的规格
后者是前者的一种实现
ECMAScript 方言还有 Jscript 和 ActionScript
ES6 与 ECMAScript 2015 的关系
ES6 一个历史名词,一个泛指
5.1版以后的 JavaScript 的下一代标准 涵盖了ES2015、ES2016、ES2017等等
ES2015 则是正式名
特指该年发布的正式版本的语言标准
语法提案的批准流程
https://github.com/tc39/ecma262
Stage 0 - Strawman(展示阶段)
Stage 1 - Proposal(征求意见阶段)
Stage 2 - Draft(草案阶段)
Stage 3 - Candidate(候选人阶段)
Stage 4 - Finished(定案阶段)
ECMAScript 的历史
部署进度
ES 6 支持
http://kangax.github.io/compat-table/es6/
Node 是 JavaScript 的服务器运行环境
查看 Node 已经实现的 ES 6 特性
node --v8-options | grep harmony
Babel 转码器
将 ES 6 代码转为 ES 5 代码
配置文件.babelrc
根目录
设置转码规则和插件
presets字段设定转码规则
Traceur 转码器
ES 6 → ES 5
2. let 和 const 命令
let 命令
基本用法
声明变量
for循环的计数器
解决for循环中计数器使用var声明的问题
原理
计数器:i,之本轮有效(相当于新变量)
根据JavaScript引擎记录的上次循环的值初始化本轮循环的值(计数器:i)
循环变量是父作用域,循环体为单独子作用域
不存在变量提升
var命令存在变量提升
let声明的变量一定要在声明后使用(ReferenceError)
暂时性死区(temporal dead zone, TDZ)
ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域(ReferenceError)
定义:在代码块内,使用let命令声明变量之前,该变量都是不可用的
typeof不再是一个百分之百安全的操作
目的:减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为
本质:当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
不允许重复声明
不允许在相同作用域内,重复声明同一个变量
不能在函数内部重新声明参数
块级作用域
引入的原因
ES 6 的块级作用域
块级作用域与函数式声明
do表达式
块级作用域的本质
一个语句
无返回值
提案-可将块级作用域变表达式
有返回值
do
const命令
只读常量
不能改变[TypeError]
声明时必须初始化[SyntaxError]
作用域
块级作用域(与let命令相同)[ReferenceError]
无变量提升,暂时性死区[ReferenceError]
不可重复声明[SyntaxError]
顶级对象属性
顶层对象
浏览器环境: window对象
Node: global
顶层对象的属性和全局变量等价(ES 5中)
顶层对象的属性和全局变量挂钩导致的问题
无法编译时报错
容易创建全局变量
不利于模块化编程
指代不明
全局变量与顶层对象的属性逐步脱钩(ES 6)
global对象
存在的问题:顶层对象的实现不统一
this变量的局限性
2种折中解决方案
一个提案:引入global作为顶层对象
垫片库:system.global
3. 字符串的扩展
字符的Unicode表示法
ES 5:\uxxxx形式表示一个字符
限于Unicode 码点在\u0000~\uFFFF之间的字符
ES 6:码点放入大括号
JavaScript 6种方法表示一个字符
'z'
'\z'
'\172'
'\x7A'
'\u007A'
'\u{7A}'
codePointAt
定义在字符串的实例对象
ES 5:charAt
4个字节的字符,字符串长度会误判为2
无法读取整个字符
ES 5:charCodeAt
只能分别返回前两个字节和后两个字节的值
codePointAt:会正确返回32位的UTF-16字符的码点
codePointAt:返回的是十进制值的码点
codePointAt方法的参数问题
字符串位置序号不准确
使用for...of循环,能正确识别32位的UTF-16字符
测试一个字符由两个字节还是由四个字节组成
String.fromCodePoint()
定义在String对象
ES 5:String.fromCharCode
从码点返回对应字符
不能识别32位的UTF-16字符,即大于0xFFFF的码点
ES 6:String.fromCodePoint
识别大于0xFFFF的字符
作用:与codePointAt方法相反
多个参数:合并成一个字符串返回
fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上
字符串的遍历器接口
for...of
部署了遍历器接口
可识别大于0xFFFF的码点
at()
ES 5:charAt
返回字符串给定位置的字符
不能识别码点大于0xFFFF的字符
提案:at()
垫片
https://github.com/es-shims/String.prototype.at
normalize()
标准等价:视觉和语义上的等价
语调符号和重音符号
带重音符号的字符
合成符号
原字符与重音符号的合成
Unicode 正规化
normalize()
将字符的不同表示方法统一为同样的形式
参数:指定normalize的方式
标准等价合成
标准等价分解
兼容等价合成
兼容等价分解
不能识别三个或三个以上字符的合成
正则表达式,通过Unicode编号区间判断
includes(), startsWith(), endsWith()
includes():表示是否找到了参数字符串
startsWith():参数字符串是否在源字符串的头部
endsWith():参数字符串是否在源字符串的尾部
第二个参数:开始搜索的位置
endsWith:对前n个字符
includes & startsWith:从第n个位置直到字符串结束
repeat()
/** * str: String * n: Number */ let resultString = str.repeat(n);
将字符串str重复n次并返回
n:如果是小数,会被取整
n:负数或者Infinity,RangeError
因为先进行取整运算,(-1, 0]的小数,则等同于0
n:NaN等同于0
n:字符串,转换成数字
padStart(), padEnd()
/** * str: String 原字符串 * targetLength: Number 指定的最小长度 * padString: String 补全字符串 */ str.padStart(targetLength [, padString]) str.padEnd(targetLength [, padString])
字符串补全长度
padStart:头部补全
padEnd:尾部补全
str.length≥targetLength ; return str;
padString.length+str.length≥targetLength, 截去超出位数的padString
省略第二个参数padString,使用空格补全
padStart:数值补全指定位数
padStart:提示字符串格式
模板字符串
模板
ES 5: 字符串拼接
ES 6:模板字符串
增强版的字符串,用反引号(`)标识
1. 普通字符串
2. 定义多行字符串
空格和换行,将被保留
3. 字符串中嵌入变量
变量名写在${}之中
${ JavaScript表达式, 进行运算, 引用对象属性, 调用函数 }
不是字符串,将按照一般的规则转为字符串
没有声明,将报错[ReferenceError]
嵌套
需要时执行
实例:模板编译
标签模板
模板字符串紧跟在一个函数名后面
该函数将被调用来处理这个模板字符串
函数调用的一种特殊形式
标签:函数
模板字符串:参数
模板字符里面有变量
将模板字符串先处理成多个参数,再调用函数
过滤HTML字符串,防止用户输入恶意内容
多语言转换(国际化处理)
在JavaScript语言之中嵌入其他语言
String.raw()
处理模板字符串
一个斜杠都被转义的字符串
斜杠已经转义,不做任何处理
正常的函数
第一个参数:具有raw属性的对象,值是一个数组
模板字符串的限制
4.变量的解构赋值
1. 数组的解构赋值
基本用法
本质:模式匹配
等号两边的模式相同,左边的变量就会被赋予对应的值
解构不成功,变量的值就等于undefined
不完全解构
等号左边的模式,只匹配一部分的等号右边的数组
报错
等号的右边不是数组(或者严格地说,不是可遍历的结构
某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值
默认值
分支主题 8
不严格等于undefined,默认值是不会生效的
一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值
可以引用解构赋值的其他变量,但该变量必须已经声明
2. 对象的解构赋值
数组的元素是按次序排列的,变量的取值由它的位置决定;
对象的属性没有次序,变量必须与属性同名,才能取到正确的值
如果变量名与属性名不一致
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" };
foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。
baz // "aaa"
foo // error: foo is not defined
以用于嵌套结构的对象
3. 字符串的解构赋值
4. 数值和布尔值的解构赋值
等号右边是数值和布尔值,则会先转为对象
解构赋值的规则
等号右边的值不是对象或数组,就先将其转为对象
undefined和null无法转为对象,所以对它们进行解构赋值,都会报错
5. 函数参数的解构赋值
函数参数的解构也可以使用默认值
参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值
6. 圆括号问题
ES6 规则:有可能导致解构的歧义,就不得使用圆括号
建议:只要有可能,就不要在模式中放置圆括号
不能使用圆括号
(1)变量声明语句
(2)函数参数
属于变量声明
(3)赋值语句的模式
可以使用圆括号
赋值语句的非模式部分
赋值语句
圆括号都不属于模式的一部分
7. 用途
(1)交换变量的值
简洁
易读
语义清晰
(2)从函数返回多个值
函数
返回:只能一个值
返回多个值:返回数组或对象
(3)函数参数的定义
对应:一组参数与变量名
(4)提取 JSON 数据
(5)函数参数的默认值
(6)遍历 Map 结构
Map 原生支持 Iterator 接口
(7)输入模块的指定方法
5.数组的扩展
扩展运算符
...
可看作rest参数的逆运算
将数组转为用逗号分隔的参数列表
主要用于函数调用
可与正常函数参数结合使用
后可放置表达式
空数组不产生效果
替代数组的apply方法
Math.max(...[])
[].push(...[])
new Date(...[2017,7,12])
应用
合并数组
与解构赋值结合
函数返回值
字符串
实现Iterator接口的对象
Map和Set结构,Generator函数
Array.from()
Array.of()
数组实例的copyWithin()
数组实例的find()和findIndex()
数组实例的fill()
数组实例的entries(), keys() 和 values()
数组实例includes()
数组的空位
6. 对象的扩展
1. 属性的简洁表示法
属性简写
ES6 允许在对象之中,直接写变量
属性名为变量名, 属性值为变量的值
方法简写
函数的返回值
CommonJS 模块输出一组变量
属性的赋值器(setter)和取值器(getter)
简洁写法的属性名总是字符串
Generator 函数,前面需要加上星号
2. 属性名表达式
JavaScript 定义对象的属性
一、直接用标识符作为属性名
二、表达式作为属性名
表达式放在方括号之内
字面量方式定义对象(使用大括号)
ES5
:只能使用方法一(标识符)定义属性
ES6
允许使用方法二(表达式)作为对象的属性名,即把表达式放在方括号内
属性名表达式与简洁表示法,不能同时使用,会报错
属性名表达式如果是一个对象,默认情况下会自动将对象转为字符串[object Object]
3. 方法的 name 属性
函数的name属性,返回函数名
如果对象的方法使用了取值函数(getter)和存值函数(setter)
name属性不是在该方法上面
在方法的属性的描述对象的get和set属性上面
返回值是方法名前加上get和set
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo'); descriptor.get.name // "get foo" descriptor.set.name // "set foo"
特殊情况
一、bind方法创造的函数,name属性返回bound加上原函数的名字
二、Function构造函数创造的函数,name属性返回anonymous
对象的方法是一个 Symbol 值,那么name属性返回的是这个 Symbol 值的描述
"[description]"
""
4. Object.is()
比较
ES5
相等运算符(==)
自动转换数据类型
严格相等运算符(===)
NaN不等于自身
+0等于-0
ES6
同值相等
比较两个值是否严格相等
与严格比较运算符(===)的行为基本一致
一、是+0不等于-0
二、是NaN等于自身
部署Object.is
Object.defineProperty(Object, 'is', { value: function(x, y) { if (x === y) { // 针对+0 不等于 -0的情况 return x !== 0 || 1 / x === 1 / y; } // 针对NaN的情况 return x !== x && y !== y; }, configurable: true, enumerable: false, writable: true });
5. Object.assign()
对象的合并
将源对象(source)的所有可枚举属性,复制到目标对象(target)
参数
第一个参数是:目标对象
后面的参数都是:源对象
同名属性覆盖
如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性
只有一个参数
参数不是对象
先转成对象,然后返回
参数是对象
直接返回
undefined、null
undefined、null 无法转成对象
报错
如果非对象参数出现在源对象的位置(即非首参数)
首先,这些参数都会转成对象,如果无法转成对象,就会跳过
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错
除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果
只有字符串的包装对象,会产生可枚举属性
布尔值、数值、字符串分别转成对应的包装对象,可以看到它们的原始值都在包装对象的内部属性[[PrimitiveValue]]上面,这个属性是不会被Object.assign拷贝的
属性名为 Symbol 值的属性,也会被Object.assign拷贝
拷贝的属性
有限制的
只拷贝源对象的自身属性(不拷贝继承属性)
不拷贝不可枚举的属性(enumerable: false)
注意点
(1)浅拷贝
如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
(2)同名属性的替换
函数库提供Object.assign的定制版本
Lodash 的_.defaultsDeep方法
(3)数组的处理
视为对象
(4)取值函数的处理
Object.assign只能进行值的复制
要复制的值是一个取值函数,那么将求值后再复制
存值函数(setter)不复制
常见用途
(1)为对象添加属性
(2)为对象添加方法
(3)克隆对象
不保持继承链
只能克隆原始对象自身的值
不能克隆它继承的值
保持继承链
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
(4)合并多个对象
(5)为属性指定默认值
浅拷贝问题
最好都是简单类型,不要指向另一个对象
否则,默认对象的该属性很可能不起作用
6. 属性的可枚举性和遍历
可枚举性
描述对象
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为
Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象
可枚举性
描述对象的enumerable属性,称为”可枚举性“
忽略enumerable为false的属性的操作
for...in循环:只遍历对象自身的和继承的可枚举的属性。
会返回继承的属性
Object.keys():返回对象自身的所有可枚举的属性的键名。
JSON.stringify():只串行化对象自身的可枚举的属性。
Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举
最初目的
让某些属性可以规避掉for...in操作
ES6 规定:所有 Class 的原型的方法都是不可枚举的
尽量不要用for...in循环,而用Object.keys()代替
操作中引入继承的属性会让问题复杂化
属性的遍历
5 种方法
(1)for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)
(2)Object.keys(obj)
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名
(3)Object.getOwnPropertyNames(obj)
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名
(4)Object.getOwnPropertySymbols(obj)
返回一个数组,包含对象自身的所有 Symbol 属性的键名
(5)Reflect.ownKeys(obj)
返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举
遵守:同样的属性遍历的次序规则
首先遍历所有数值键,按照数值升序排列
其次遍历所有字符串键,按照加入时间升序排列
最后遍历所有 Symbol 键,按照加入时间升序排列
7. Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptor
返回某个对象属性的描述对象(descriptor)
Object.getOwnPropertyDescriptors
ES2017 引入
返回指定对象所有自身属性(非继承属性)的描述对象
实现
function getOwnPropertyDescriptors(obj) { const result = {}; for (let key of Reflect.ownKeys(obj)) { result[key] = Object.getOwnPropertyDescriptor(obj, key); } return result; }
引入目的
解决Object.assign()无法正确拷贝get属性和set属性的问题
Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法
正确拷贝
Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法
浅拷贝
配合Object.create方法,将对象属性克隆到一个新对象
8. __proto__属性,Object.setPrototypeOf(),Object.getPrototypeOf()
JavaScript 语言的对象继承是通过原型链实现的
__proto__属性
用来读取或设置当前对象的prototype对象
所有浏览器(包括 IE11)都部署了这个属性
不建议使用这个属性
本质上是一个内部属性
没有写入 ES6 的正文,而是写入了附录
不是一个正式的对外的 API,只是由于浏览器广泛支持,才被加入了 ES6
标准明确规定
只有浏览器必须部署这个属性,其他运行环境不一定需要部署,而且新的代码最好认为这个属性是不存在的
代替
Object.setPrototypeOf()(写操作)
Object.getPrototypeOf()(读操作)
Object.create()(生成操作)
实现
__proto__调用的是Object.prototype.__proto__
Object.defineProperty(Object.prototype, '__proto__', { get() { let _thisObj = Object(this); return Object.getPrototypeOf(_thisObj); }, set(proto) { if (this === undefined || this === null) { throw new TypeError(); } if (!isObject(this)) { return undefined; } if (!isObject(proto)) { return undefined; } let status = Reflect.setPrototypeOf(this, proto); if (!status) { throw new TypeError(); } }, }); function isObject(value) { return Object(value) === value; }
如果一个对象本身部署了__proto__属性,该属性的值就是对象的原型
Object.setPrototypeOf
与__proto__相同
用来设置一个对象的prototype对象,返回参数对象本身
第一个参数不是对象,会自动转为对象
由于返回的还是第一个参数,所以这个操作不会产生任何效果
undefined和null无法转为对象
第一个参数是undefined或null,就会报错
Object.getPrototypeOf
用于读取一个对象的原型对象
如果参数不是对象,会被自动转为对象
如果参数是undefined或null,它们无法转为对象,所以会报错。
9. super 关键字
this关键字总是指向函数所在的当前对象
super指向当前对象的原型对象
表示原型对象时,只能用在对象的方法之中
10. Object.keys(),Object.values(),Object.entries()
Object.keys
ES5 引入
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名
ES2017
Object.values和Object.entries
11. 对象的扩展运算符
扩展运算符(...)
ES2017 将这个运算符引入了对象
(1)解构赋值
(2)扩展运算符
12. Null 传导运算符
问题:读取对象内部的某个属性,需要判断对象是否存在
解决
引入“Null 传导运算符”提案
https://github.com/claudepache/es-optional-chaining
四种用法
一、obj?.prop // 读取对象属性
二、obj?.[expr] // 同上
三、func?.(...args) // 函数或对象方法的调用
四、new C?.(...args) // 构造函数的调用
写法
obj?.prop,方便编译器能够区分三元运算符?:
7.Set和Map数据结构
Set
数据结构
类似于数组
值都唯一
Set 本身:构造函数
接受一个数组(具有 Iterable 接口)作为参数
不会发生类型转换
在 Set 内部,两个NaN是相等
Same-value equality
类似于精确相等运算符(===)
NaN等于自身
精确相等运算符认为NaN不等于自身
两个对象总是不相等的
两个空对象
Set 结构的实例和方法
属性
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
方法
操作方法
add(value):添加某个值,返回Set结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。
Object结构和Set结构的不同写法
Array.from: Set => 数组
遍历方法
遍历操作
遍历顺序→插入顺序
Set:保存一个回调函数列表
遍历方法
返回:遍历器对象
键名、键值相同
keys():键名
values():键值
entries():键值对
实例默认可遍历;默认遍历器:values方法
可省略values方法,用for...of遍历
无返回值
forEach():使用回调函数遍历每个成员
setObj.forEach(callbackfn[, thisArg])
callbackfn(键值, 键名, 集合本身)
thisArg:绑定的this对象
遍历的应用
数组去重
扩展运算符(...)
[].map & [].filter
集合
并集
交集
差集
改变 Set 结构
映射重新赋值
Array.from
WeakSet
含义
与 Set 类似
成员:只能是对象
对象:弱引用
垃圾回收机制不考虑
垃圾回收机制
依赖引用计数
引用次数≠0,不会释放该内存
内存泄漏
WeakSet 不可遍历
成员:随时消失
不适合引用
成员数不确定
语法
WeakSet:构造函数
接受一个数组(具有 Iterable 接口)作为参数
数组成员 => WeakSet 实例对象的成员
方法
WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,某个值是否在 WeakSet 实例之中。
应用
存放一组对象,以及存放跟对象绑定的信息
对象消失 => 引用消失
储存 DOM 节点
可实现:实例方法,只能的实例上调用
Map
WeakMap
8.Proxy
概述
元编程
ES 6:var proxy = new Proxy(target, handler);
new Proxy():生成一个Proxy实例
target:对象,拦截的目标
handler:对象,定制拦截行为
Proxy 实例的方法
Proxy.revocable()
this 问题
实例:Web 服务的客户端
9.Promise 对象
Promise 的含义
Promise对象
特点
对象的状态不受外界影响
一旦状态改变,就不会再变
状态
Pending(进行中)
Fulfilled(已成功)
Rejected(已失败)
缺点
无法取消Promise
不设置回调函数,Promise内部抛出的错误,不会反应到外部
当处于Pending状态时,无法得知目前进展到哪一个阶段
基本用法
一个构造函数
Promise.prototype.then()
Promise.prototype.catch()
Promise.all()
多个 Promise 实例 => 一个新的 Promise 实例
Promise.all(iterable)
Promise.race()
Promise.resolve()
对象 => Promise对象
参数
Promise实例
thenable对象
非thenable对象 或 非对象
无参数
返回:Promise对象 状态:Resolved
Promise.reject()
Promise.reject(reason)
返回:一个新的 Promise 实例
状态:rejected
执行:本轮“事件循环”(event loop)的结束
setTimeout(fn, 0)
下一轮“事件循环”开始时执行
两个有用的附加方法
done()
处于回调链的尾端,保证抛出任何可能出现的错误
finally()
指定不管Promise对象最后状态如何,都会执行的操作
一个普通的回调函数作为参数,该函数不管怎样都必须执行
应用
图片加载
Generator函数与Promise的结合
Promise.try()
1.同步函数同步执行 2.异步函数异步执行 3.并具有统一的 API
async函数
new Promise()
提案:Promise.try()
Promise.try包装
更好地管理异常
统一用promise.catch()捕获所有同步和异步的错误
模拟try代码块
10.Module 的加载实现
11.编程风格
块级作用域
let 取代 var
变量应该只在其声明的代码块内有效
var 命令存在变量提升
全局常量和线程安全
const 优于 let
全局环境,不应该设置变量,只应设置常量
子主题 2
字符串
使用单引号或反引号,不使用双引号
动态字符串使用反引号
解构赋值
使用数组成员对变量赋值时,优先使用解构赋值
函数的参数如果是对象的成员,优先使用解构赋值
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值
便于以后添加返回值,以及更改返回值的顺序
对象
单行定义的对象,最后一个成员不以逗号结尾
多行定义的对象,最后一个成员以逗号结尾
对象尽量静态化,一旦定义,就不得随意添加新的属性
如果添加属性不可避免,要使用Object.assign方法
如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义
对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写
数组
使用扩展运算符(...)拷贝数组
使用Array.from方法,将类似数组的对象转为数组
函数
立即执行函数可以写成箭头函数的形式
需要使用函数表达式的场合,尽量用箭头函数代替
更简洁,而且绑定了this
箭头函数取代Function.prototype.bind
简单的、单行的、不会复用的函数,建议采用箭头函数
如果函数体较为复杂,行数较多,还是应该采用传统的函数写法
所有配置项都应该集中在一个对象,放在最后一个参数
布尔值不可以直接作为参数
使用rest运算符(...)代替arguments变量
rest运算符显式表明你想要获取参数
arguments是一个类似数组的对象
rest运算符可以提供一个真正的数组
使用默认值语法设置函数参数的默认值
Map结构
区分Object和Map
模拟现实世界的实体对象时,使用Object
key: value的数据结构,使用Map
Map有内建的遍历机制
Class
用Class,取代需要prototype的操作
Class的写法更简洁,更易于理解
使用extends实现继承
更简单,不会有破坏instanceof运算的危险
模块
使用import取代require
使用export取代module.exports
只有一个输出值,使用export default
多个输出值,不使用export default
export default与export不要同时使用
不要在模块输入中使用通配符
确保你的模块之中,有一个默认输出(export default)
如果模块默认输出一个函数,函数名的首字母应该小写
如果模块默认输出一个对象,对象名的首字母应该大写
ESLint的使用
ESLint是一个语法规则和代码风格的检查工具
保证写出语法正确、风格统一的代码