Understanding ECMAScript6(中)
Part 1:Set 和 Map
Set 数据结构
- Set 是无重复值的有序列表。
可以对它包含的数据快速访问。
使用new Set()
来创建一个 Set 数据结构👇
let set = new Set();
使用 add()
方法为 Set 添加项目;
它有一个 size 属性可查看其中包含多少项👇
set.add(66);
set.add('66');
set.size // 2
👆 Set 不使用强制转换来判断值是否重复,数字66和字符串66是两个独立的项。
如果使用 add()
重复添加了某项,之后的调用会被忽略👇
- 使用
has()
判断某个项目是否存在👇
- 使用
delete()
移除一个项目👇
- 使用
clear()
清空整个 Set👇
- 用数组初始化一个 Set👇
因为 Set 是无重复值的列表,所以只保留了1,3,4三个值。
🚫用其它类型数据尝试使用类似数组初始化 Set 都是行不通的。
Set 的 forEach()方法
forEach()
方法被传递一个回调函数,该回调接收三个参数:
-
1: Set 中下一个位置的值
-
2: 与第一个参数相同的值
-
3: Set 本身
Paste_Image.png
与其它拥有forEach()
方法的数据结构(也就是数组和 Map)最明显的不同是:Set 的forEach()
方法接收的回调函数的参数,很奇怪,为什么前两个参数要一样?
其实就是为了保持forEach()
一致。
为此,ES6特意为 Set 中的每个项目同时认定为“键”与“值”。
-
Set 有点是可以很方便地追踪一个值,并且可以用
forEach()
按顺序处理每一项,但它无法像数组那样用索引来访问某个值。 -
我们可以将它转换成数组👇
👆使用
...
扩展运算符接收 Set 对象,同时,Set 也已经将数组去重复。💡这是一个非常实用的数组去重复技巧。
Map 数据结构
- Map 是键值对有序列表
- 使用
set()
方法为 Map 添加一对键值
let map = new Map();
map.set('name', 'Rogger');
map.set('year', 2017);
Map.set()
和 Set.add()
有些相似,需要注意的是,Map.set() 多次设置一个项目时,后者覆盖前者👇
- 使用
get()
方法访问某个值
-
拥有与 Set 一样的三个方法和一个属性:
Map.has()
Map.delete()
Map.clear()
Map.size
-
使用数组初始化 Map
let map = new Map( [ ['name', 'Bean'], ['age', 42] ] );
👆不同于数组初始化 Set 之处是,数组初始化 Map 时,数组中的每一项也必须是数组。
因为这样才能准确表达 Map 中的每个项目都是键值对。
Map 的 forEach()方法
forEach()
方法接收的回调函数同样接收三个参数:
- 1:Map 中下一个位置的值
- 2:该值对应的键
- 3:Map 本身
Part 2: 增强的数组功能
创建数组的新方法
-
Array.of()
方法
之前我们使用new Array()
构造器创建一个数组时,传入的参数类型和数量是可以影响最终结果的。
传入单个数值参数时,数组长度被设置为该参数,
传入单个非数值参数时,参数则成为该数组的项👇
Paste_Image.png
当传入多个参数时(无论数值与否),所有参数都成为数组的项👇
Paste_Image.png Paste_Image.pngES6 中引入的
Array.of()
方法,接收的参数将永远作为数组的项👇
Paste_Image.png
Paste_Image.png
Array.of()
方法避免了 new Array()
构造器可能造成的混乱,今后可以考虑用 Array.of()
来代替构造器。
-
Array.from()
方法
将可迭代对象或者类数组对象作为参数传入Array.from()
就能返回一个数组
常见场景是,将arguments
转化为数组👇
Paste_Image.png
将 nodeList 转换为数组👇
- 可以向
Array.from
传入一个用作映射的函数作为第二个参数👇
Paste_Image.png
如此便完成了一个批量处理👆
数组新方法
-
find()
和findIndex()
方法
接收一个回调函数,该函数在给定元素满足定义的时候返回 true。
当回调函数第一次返回 true 时,find()/findIndex()
便停止查找。
不同之处是find()
返回匹配的值,findIndex()
返回匹配值的位置👇
-
fill()
方法
该方法用指定值来填充数组👇
Paste_Image.png
接收第二个可选参数作为填充起始位置,接收第三个可选参数作为填充结束位置(填充范围不包含结束位置)👇
-
copyWithin()
方法
copyWithin()
方法允许在数组内部“复制粘贴”自身元素,它接收两个参数,一是从何位置开始“粘贴”,二是从何位置开始“复制”:
👆从数组的第2个位置开始粘贴,从数组第0个位置开始复制(一直复制到数组末尾)
可以传入第三个可选的参数来控制多少元素被覆盖👇
Part 3:生成器与迭代器
可迭代对象与 for-of
循环
在过去我们遍历一个数组时,需要这样👇
Paste_Image.png在 ES6 中,所有集合对象(数组,Set,Map)都是可迭代对象,可配合新增的 for-of
使用👇
与传统
for
循环相比,for-of
更容易,因为它不需要计数器也不必考虑循环何时结束。它会从迭代器中读取所有数据后退出循环。如果简单地迭代数组或集合的值,使用
for-of
更好,将传统的 for
留给更复杂的逻辑控制。
集合的迭代器
ES6 中集合迭代器(数组,Set,Map)拥有三种内置的迭代器:keys()
,value()
,entries()
。
- 可以显式指定集合使用何种迭代器。
-
keys()
返回集合中的键
对于数组,返回数值类型的键;对于 Set 返回键值相同的迭代器;对于 Map 返回不重复的键👇
-
entries()
返回双项目数组,代表键和值👇
- 数组和 Set 的默认迭代器是
values()
,Map 的默认迭代器是entries
。
字符串的迭代器
字符串同样拥有默认迭代器👇
Paste_Image.png
NodeList 的迭代器
下面代码可以打印页面中所有 div 的 id 值
let node = document.getElementsByTagName('div');
for(let div of node){
console.log(div.id);
}
自定义迭代器
了解它之前,要先说说用于返回迭代器的函数——生成器:
生成器用放在 function
关键字之后的 *
表示,并使用新的关键字 yield
来控制“节奏”👇
生成器可以像普通函数那样被调用,但返回的则是一个迭代器了👇
Paste_Image.png
yield
指定了迭代器被 next()
方法调用时的返回值👇Paste_Image.png
所有迭代器都有
next()
方法,它返回两个属性:值 value
和 布尔类型的 done
,当 done
值为 true 时表示迭代器没有更多的返回了。也可以用函数表达式的方式创建一个生成器👇
Paste_Image.png
-
作为方法的生成器的书写方法
ES5 中的传统写法👇
Paste_Image.png
ES6 中的简写写法👇
Paste_Image.png -
要注意的是,
yield
关键字必须严格在生成器的内部,即是是生成器内部的函数内也不行👇
委托生成器
使用 yield
和 *
配合,将生成器包裹于另一个生成器中,就获得了一个委托生成器👇
生成器委托对迭代器的行为进行了良好的组织。
Part 4:符号
-
ES5 中的基本类型:String/Number/Boolean/Undefined/Null/Object。
ES6 引入了新的基本类型:Symbol(符号)。 -
符号没有字面量形式,这是 JS 中独一无二的。
使用Symbol()
创建一个符号👇
-
Symbol()
接收一个参数作为它的描述,这个描述内容不能访问,但可以用来调试👇
-
它作为对象属性时,不可枚举👇
Paste_Image.png
可以在需要使用“计算属性名”的场景中使用符号👆
💡在对象内部使用符号时,需要使用[]
来操作。 -
使用
Paste_Image.pngSymbol.for()
登记一个符号供全局共享👇
👆通过向Symbol.for()
传入参数,sy3/sy4 引用了同一个符号。
Symbol.for()
调用时不会先返回新符号,而是在全局注册表中查找是否有已存在的符号,如有则返回,如没有则新建👇
Paste_Image.png
❓生产中的用处
一些知名符号:
Symbol.hasInstance
:供 instanceof 运算符使用,用于判断继承关系。
Symbol.isConcatSpreadable
:布尔类型值,在集合参数传递给 concat()
方法时,指定集合是否展开。
Symbol.match
:比较字符串。
Symbol.replace
:替换字符串。
Symbol.search
:定位字符串。
Symbol.split
:用于分割字符串。
Symbol.species
:用于派生对象构造器。
Symbol.toPrimitive
:返回对象对应的基本类型。
Symbol.iterator
:返回迭代器的一个方法。
-
Symbol.iterator
迭代符号
尝试直接用for-of
迭代一个对象字面量行不通👇
Paste_Image.png
使用迭代符号改写后的 obj 👇
Paste_Image.png
可迭代的数据集合(数组,Set,Map)之所以可以直接迭代就是因为已经部署好了[Symbol.iterator]
原因在于,这些数据结构原生部署了Symbol.iterator属性,另外一些数据结构没有。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象。——阮一峰
本节完
Understanding ECMAScript6(上)
Understanding ECMAScript6(下)