let/const
let/const
用于声明变量,替代老语法的var
关键字,它的用法与var
类似,但是所声明的变量只在所在的代码块中有效。
let/const
与var
的主要区别:
- 不允许重复声明
- 未定义就使用会报错:
let/const
不存在变量提升现象 - 暂时性死区:在代码块内使用
const命令
和let命令
声明变量之前,该变量都不可用
const
与let
不相同的是,const
声明的是一个只读常量。
const
的特点:
const
与let
不同,const
声明后必须立马赋值,只声明不赋值就会报错const
是一个只读常量,并不是变量的值不改变,而是变量指向的那个内存地址不改变。- 对于简单类型的数据(数值、字符串、布尔值),就相当于常量
- 对于复合类型的数据(数组、对象),变量指向内存地址,
const
实际保存的是指向实际数据的指针,它只能保证指针不变,不能保证,指针里的内容不变,
解构赋值
多种解构
字符串解构
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
数值和布尔值解构
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
对象解构
对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
形式:const { x, y } = { x: 1, y: 2 }
默认:const { x, y = 2 } = { x: 1 }
改名:const { x, y: z } = { x: 1, y: 2 }
数组解构
只要某种数据结构具有Iterator接口
就可采用数组形式的解构赋值
形式:const [x, y] = [1, 2]
默认:const [x, y = 2] = [1]
函数参数解构
//数组参数解构
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
//对象参数解构且有默认值
function move({x = 0, y = 0} = {}) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
应用场景
-
交换变量值:
[x, y] = [y, x]
-
返回函数多个值:
const [x, y, z] = Func()
-
定义函数参数:
Func([1, 2])
-
提取JSON数据:
const { name, version } = packageJson
-
定义函数参数默认值:
function Func({ x = 1, y = 2 } = {}) {}
-
遍历Map结构:
for (let [k, v] of Map) {}
-
输入模块指定属性和方法:
const { readFile, writeFile } = require("fs")
重点
- 匹配模式:只要等号两边的模式相同,左边的变量就可以赋给右边
- 解构赋值规则:只要右边不是对象或者数组,就会将其转换为对象
- 解构不成功时,变量的值为
undifined
undifined
与null
无法转为对象,因此无法赋值
箭头函数
ES6 允许使用箭头(=>)定义函数,简化定义函数
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
- 无参数:
() => {}
- 单个参数:
x => {}
- 多个参数:
(x, y) => {}
- 解构参数:
({x, y}) => {}
重点
-
函数体内的
this
对象,就是定义时所在的对象,而不是使用时所在的对象。 -
不可以当作构造函数,也就是说,不可以使用
new
命令,否则会抛出一个错误。 -
不可以使用
arguments
对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
数组的扩展
扩展运算符(...):转换数组为用逗号分隔的参数序列([...arr]
,相当于rest/spread参数
的逆运算)
Array.from():转换具有Iterator接口
的数据结构为真正数组,返回新数组
类数组对象:包含length的对象
、Arguments对象
、NodeList对象
可遍历对象:String
、Set结构
、Map结构
、Generator函数
Array.of():转换一组值为真正数组,返回新数组
copyWithin():把指定位置的成员复制到其他位置,返回原数组
find():返回第一个符合条件的成员
findIndex():返回第一个符合条件的成员索引值
fill():根据指定值填充整个数组,返回原数组
keys():返回以索引值为遍历器的对象
values():返回以属性值为遍历器的对象
entries():返回以索引值和属性值为遍历器的对象
数组空位:ES6明确将数组空位转为undefined
(空位处理规不一,建议避免出现)
扩展运算符的应用
克隆数组:const arr = [...arr1]
合并数组:const arr = [...arr1, ...arr2]
拼接数组:arr.push(...arr1)
代替apply:Math.max.apply(null, [x, y])
=> Math.max(...[x, y])
转换字符串为数组:[..."hello"]
转换类数组对象为数组:[...Arguments, ...NodeList]
转换可遍历对象为数组:[...String, ...Set, ...Map, ...Generator]
与数组解构赋值结合:const [x, ...rest/spread] = [1, 2, 3]
计算Unicode字符长度:Array.from("hello").length
=> [..."hello"].length
Set
- 定义:类似于数组的数据结构,成员值都是唯一且没有重复的值
- 声明:
const set = new Set(arr)
- 入参:具有
Iterator接口
的数据结构 - 属性
- constructor:构造函数,返回Set
- size:返回实例成员总数
- 方法
- add():添加值,返回实例
- delete():删除值,返回布尔
- has():检查值,返回布尔
- clear():清除所有成员
- keys():返回以属性值为遍历器的对象
- values():返回以属性值为遍历器的对象
- entries():返回以属性值和属性值为遍历器的对象
- forEach():使用回调函数遍历每个成员
应用场景
- 去重字符串:
[...new Set(str)].join("")
- 去重数组:
[...new Set(arr)]
或Array.from(new Set(arr))
- 集合数组
- 声明:
const a = new Set(arr1)
、const b = new Set(arr2)
- 并集:
new Set([...a, ...b])
- 交集:
new Set([...a].filter(v => b.has(v)))
- 差集:
new Set([...a].filter(v => !b.has(v)))
- 声明:
- 映射集合
- 声明:
let set = new Set(arr)
- 映射:
set = new Set([...set].map(v => v * 2))
或set = new Set(Array.from(set, v => v * 2))
- 声明:
重点难点
- 遍历顺序:插入顺序
- 没有键只有值,可认为键和值两值相等
- 添加多个
NaN
时,只会存在一个NaN
- 添加相同的对象时,会认为是不同的对象
- 添加值时不会发生类型转换(
5 !== "5"
) keys()
和values()
的行为完全一致,entries()
返回的遍历器同时包括键和值且两值相等
WeakSet
- 定义:和Set结构类似,成员值只能是对象
- 声明:
const set = new WeakSet(arr)
- 入参:具有
Iterator接口
的数据结构 - 属性
- constructor:构造函数,返回WeakSet
- 方法
- add():添加值,返回实例
- delete():删除值,返回布尔
- has():检查值,返回布尔
应用场景
- 储存DOM节点:DOM节点被移除时自动释放此成员,不用担心这些节点从文档移除时会引发内存泄漏
- 临时存放一组对象或存放跟对象绑定的信息:只要这些对象在外部消失,它在
WeakSet结构
中的引用就会自动消
重点难点
- 成员都是
弱引用
,垃圾回收机制不考虑WeakSet结构
对此成员的引用 - 成员不适合引用,它会随时消失,因此ES6规定
WeakSet结构不可遍历
- 其他对象不再引用成员时,垃圾回收机制会自动回收此成员所占用的内存,不考虑此成员是否还存在于
WeakSet结构
中
Map
- 定义:类似于对象的数据结构,成员键是任何类型的值
- 声明:
const set = new Map(arr)
- 入参:具有
Iterator接口
且每个成员都是一个双元素数组的数据结构 - 属性
- constructor:构造函数,返回Map
- size:返回实例成员总数
- 方法
- get():返回键值对
- set():添加键值对,返回实例
- delete():删除键值对,返回布尔
- has():检查键值对,返回布尔
- clear():清除所有成员
- keys():返回以键为遍历器的对象
- values():返回以值为遍历器的对象
- entries():返回以键和值为遍历器的对象
- forEach():使用回调函数遍历每个成员
重点难点
- 遍历顺序:插入顺序
- 对同一个键多次赋值,后面的值将覆盖前面的值
- 对同一个对象的引用,被视为一个键
- 对同样值的两个实例,被视为两个键
- 键跟内存地址绑定,只要内存地址不一样就视为两个键
- 添加多个以
NaN
作为键时,只会存在一个以NaN
作为键的值 Object结构
提供字符串—值
的对应,Map结构
提供值—值
的对应
WeakMap
- 定义:和Map结构类似,成员键只能是对象
- 声明:
const set = new WeakMap(arr)
- 入参:具有
Iterator接口
且每个成员都是一个双元素数组的数据结构 - 属性
- constructor:构造函数,返回WeakMap
- 方法
- get():返回键值对
- set():添加键值对,返回实例
- delete():删除键值对,返回布尔
- has():检查键值对,返回布尔
应用场景
- 储存DOM节点:DOM节点被移除时自动释放此成员键,不用担心这些节点从文档移除时会引发内存泄漏
- 部署私有属性:内部属性是实例的弱引用,删除实例时它们也随之消失,不会造成内存泄漏
重点难点
- 成员键都是
弱引用
,垃圾回收机制不考虑WeakMap结构
对此成员键的引用 - 成员键不适合引用,它会随时消失,因此ES6规定
WeakMap结构不可遍历
- 其他对象不再引用成员键时,垃圾回收机制会自动回收此成员所占用的内存,不考虑此成员是否还存在于
WeakMap结构
中 - 一旦不再需要,成员会自动消失,不用手动删除引用
- 弱引用的
只是键而不是值
,值依然是正常引用 - 即使在外部消除了成员键的引用,内部的成员值依然存在
Promise
- 定义:Promise是一种异步编程的解决方案。从语法上来讲,Promise是一个对象,他可以获取异步操作的的消息。从本意上来讲,Promise是一个承诺,承诺过一段时间后给你一个结果。Promise有三种状态:pending(等待),fulfiled(成功),rejected(失败),状态一旦改变,就不会再变。
- 状态:
- 进行中:pending
- 已成功:fulfilled
- 已失败:rejected
- 特点:
- 对象的操作不受外界的影响
- 一旦状态改变,任何时候都会得到这个结果
- 示例:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
-
出参
- resolve:将状态从
未完成
变为成功
,在异步操作成功时调用,并将异步操作的结果作为参数传递出去 - reject:将状态从
未完成
变为失败
,在异步操作失败时调用,并将异步操作的错误作为参数传递出去
- resolve:将状态从
-
方法:
-
then():分别指定
resolved
和rejected
状态的回调函数- 第一参数:状态变为
resolved
时调用 - 第二参数:状态变为
rejected
时调用
- 第一参数:状态变为
-
catch():用于指定发生错误时的回调函数。
-
Promise.all():将多个实例包装成一个新实例,返回全部实例状态变更后的结果数组(齐变更再返回)
- 入参:具有
Iterator接口
的数据结构 - 成功:只有全部实例状态变成
fulfilled
,最终状态才会变成fulfilled
- 失败:其中一个实例状态变成
rejected
,最终状态就会变成rejected
- 入参:具有
-
Promise.race():将多个实例包装成一个新实例,返回全部实例状态优先变更后的结果(先变更先返回)
- 入参:具有
Iterator接口
的数据结构 - 成功失败:哪个实例率先改变状态就返回哪个实例的状态
- 入参:具有
-
Promise.resolve():将对象转为Promise对象(等价于
new Promise(resolve => resolve())
)- Promise实例:原封不动地返回入参
- Thenable对象:将此对象转为Promise对象并返回(Thenable为包含
then()
的对象,执行then()
相当于执行此对象的then()
) - 不具有then()的对象:将此对象转为Promise对象并返回,状态为
resolved
- 不带参数:返回Promise对象,状态为
resolved
-
Promise.reject():将对象转为状态为
rejected
的Promise对象(等价于new Promise((resolve, reject) => reject())
)
-
应用场景
-
加载图片
-
AJAX转Promise对象
重点难点
-
只有异步操作的结果可决定当前状态是哪一种,其他操作都无法改变这个状态
-
状态改变只有两种可能:从
pending
变为resolved
、从pending
变为rejected
-
一旦新建
Promise对象
就会立即执行,无法中途取消 -
不设置回调函数,内部抛错不会反应到外部
-
当处于
pending
时,无法得知目前进展到哪一个阶段 -
实例状态变为
resolved
或rejected
时,会触发then()
绑定的回调函数 -
resolve()
和reject()
的执行总是晚于本轮循环的同步任务 -
then()
返回新实例,其后可再调用另一个
then() -
then()
运行中抛出错误会被catch()
捕获 -
reject()
的作用等同于抛出错误 -
实例状态已变成
resolved
时,再抛出错误是无效的,不会被捕获,等于没有抛出 -
实例状态的错误具有
冒泡
性质,会一直向后传递直到被捕获为止,错误总是会被下一个catch()
捕获 -
不要在
then()
里定义rejected
状态的回调函数(不使用其第二参数) -
建议使用
catch()
捕获错误,不要使用then()
第二个参数捕获 -
没有使用
catch()
捕获错误,实例抛错不会传递到外层代码,即不会有任何反应
-
作为参数的实例定义了
catch()
,一旦被rejected
并不会触发Promise.all()
的catch()
-
Promise.reject()
的参数会原封不动地作为rejected
的理由,变成后续方法的参数
for...of
循环
-
定义:调用
Iterator
接口产生遍历器对象(for-of
内部调用数据结构的Symbol.iterator()
) -
遍历字符串:
for-in
获取索引
,for-of
获取值
. -
遍历数组:
for-in
获取索引
,for-of
获取值
-
遍历Set:
for-of
获取值
=>for (const v of set)
-
遍历Map:
for-of
获取键值对
=>for (const [k, v] of map)
,for-of
获得到的是一个由键
与值
构成的数组let map = new Map().set('a', 1).set('b', 2); for (let pair of map) { console.log(pair); } // ['a', 1] // ['b', 2] for (let [key, value] of map) { console.log(key + ' : ' + value); } // a : 1 // b : 2
-
遍历对象:
for-in
获取键
,for-of
需自行部署for-of
并不能直接遍历对象,如果直接遍历会报错。我们需要部署Iterator
接口。遍历对象还是使用for-in
更好一点- 使用
Object.keys
方法将对象的键名生成一个数组,然后遍历这个数组。
for (var key of Object.keys(someObject)) { console.log(key + ': ' + someObject[key]); }
- 使用 Generator 函数将对象重新包装一下。
function* entries(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } } for (let [key, value] of entries(obj)) { console.log(key, '->', value); } // a -> 1 // b -> 2 // c -> 3
- 使用
-
与
for-in
区别- 有着同
for-in
一样的简洁语法,但不会像for-in
一样会遍历原型上的属性。 for-of
会以添加顺序来进行遍历,而不会像for-in
以任意顺序遍历- 不同于
forEach()
,它可与break
、continue
和return
配合使用 - 提供遍历所有数据结构的统一操作接口
- 有着同