/*
【可迭代对象】和【for-of】循环
可迭代对象具有 Symbol.iterator属性,是一种与迭代器密切相关的对象
在ECMAScript6中,所有的集合对象(数组,Set集合以及Map集合)和字符串都是可迭代的对象,
这些对象都有默认的迭代器。
for-of 循环需要用到可迭代对象的这些功能。
*/
let values = [1, 2, 3];
for (let num of values) {
console.log(num); // 1 2 3
}
/*
for-of循环
每一次斗殴会调用可迭代对象的next()方法,并将迭代器返回的结果对象的value属性
存储在一个变量里,循环持续执行直到返回对象的done属性为true
for-of循环代码通过 values数组的Symbol.iterator方法获取迭代器, 随着迭代器的多次调用
从其返回对象的value属性读取值并存储在变量 num中,当结果对象的done属性是true时循环退出
如果只需迭代数组或者集合中的值,用for-of循环替代for循环是个不错的选择
* */
// 1. 访问默认迭代器 可以通过Symbol.iterator来访问对象默认的迭代器
values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
console.log(iterator.next()); // {value: 1, done: false}
/*
由于具有Symbol.iterator属性对象都有默认的迭代器,因此可以用来检测对象
是否为可迭代对象
*/
function isIterable(object) {
return typeof object[Symbol.iterator] === "function";
}
// 2. 创建可迭代对象
/*
默认情况下,开发者定义的对象都是不可迭代对象,当如果给Symbol.iterator属性添加一个生成器,则
可以变成可迭代对象
*/
let collection = {
items: [],
// 定义生成器函数,返回迭代元素值
* [Symbol.iterator]() {
for (let item of this.items) {
yield item;
}
}
};
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for (let x of collection) {
console.log(x); // 1 2 3
}
// 3. 内建迭代器
/**
* 迭代器是ECMAScript6的一个重要组成部分,在ECMAScript6默认为许多内建类型提供了内建迭代器,
* 只有这些内建迭代器无法完成你的目标时才需要自己创建,否则完全可以依靠内建迭代器来完成工作。
集合对象迭代器
ECMAScript6有三种类型的集合对象:数组、Map集合与 Set集合, 为了更好的访问对象中的内容
这三种对象都内建了三种迭代器:
entries(): 返回一个迭代器,其值为 多个键值对
values() : 返回一个迭代器,其值为集合的值
keys(): 返回一个迭代器,其值为集合中所有的键名
entries()迭代器:
每次调用next()方法,entries()迭代器都会返回一个数组,数组中的两个元素分别表示集合中每个
元素的键和值。
如果被遍历的对象是
数组: 第一个元素时数字类型的索引
Set集合: 第一个元素与第二个元素都是集合中的值,被同时作为键和值使用
Map集合, 第一个元素为键名
*/
let colors = ["red", "green", "blue"];
let tracking = new Set([123, 567, 90102]);
let data = new Map();
data.set("title", "learn ES6");
data.set("format", "ebook");
// 使用entries()迭代器
// 数组
for (let entry of colors.entries()) {
console.log(entry); // [0, "red"] [1,"green"] [2,"blue"]
}
// Set集合
for (let entry of tracking.entries()) {
console.log(entry); // [123, 123] [567, 567] [90102, 90102]
}
// Map集合
for (let entry of data.entries()) {
console.log(entry); // ["title", "learn ES6"] ["format", "ebook"]
}
/**
* values()迭代器
* 调用values()迭代器时会返回集合中所存的所有值
*/
// values()迭代器
// 数组
for (let value of colors.values()) {
console.log(value); // red green blue
}
// Set集合
for (let value of tracking.values()) {
console.log(value); // 123 567 90102
}
// Map集合
for (let value of data.values()) {
console.log(value); // learn ES6 ebook
}
// keys()迭代器
/**
* keys()迭代器会返回集合中存在的每一个键。如果遍历的是数组,则会返回的是数字型的键
* 如果是Set集合key和value相同,如果是Map则会返回每个独立的键
*/
// keys()迭代器
// 数组
for (let key of colors.keys()) {
console.log(key); // 0 1 2
}
// Set集合
for (let key of tracking.keys()) {
console.log(key); // 123 567 90102
}
// Map集合
for (let key of data.keys()) {
console.log(key); // title format
}
/*
* 不同集合类型的默认迭代器,在for-of循环中,如果没有显示指定使用的默认迭代器。数组和Set的默认迭代器
* 是values()方法,而 Map集合的默认迭代器是 entries()方法。
* */
for (let value of colors) {
console.log(value); // red green blue
}
for (let num of tracking) {
console.log(num); // 123 567 90102
}
for (let entry of data) {
console.log(entry); // ["title", "learn ES6"] ["format", "ebook"]
}
// 字符串迭代器
/**
* 自EMCAScript5发布以后,JavaScript字符串慢慢变得更像数组了,ES5可以通过方括号访问字符串中的字符
* text[0] 可以获取字符串text的第一个字符
* 由于方括号操作的是编码单元而非字符,因此无法正确访问双字节字符
*/
let message = "A 吉 B";
for (let i = 0, len = message.length; i < len; i++) {
console.log(message[i]); // A吉B
}
for (let c of message) {
console.log(c); // A 吉 B
}
// 1. NodeList迭代器
/**
* DOM标准中有一个NodeList类型,代表页面文档中所有元素的集合
*
* NodeList对象和数组,二者都使用length属性来表示集合中元素的数量,都可以使用方括号来访问集合中独立的元素
*
* NodeList也拥有默认迭代器,也可以应用于for-of循环
*
*/
var divs = document.getElementsByTagName("div");
for (let div of divs) {
console.log(div.id); // father son
}
// 2. 展开运算符与非数组可迭代对象
// 展开运算符(...)把Set集合换成了一个数组
let set = new Set([1, 2, 2, 3, 4, 4, 5]),
array = [...set];
/**
* 这段代码的展开运算符把Set集合的所有值填充到了一个数组字面量里,它可以操作所有可迭代对象,并根据
* 默认迭代器来选取要引用的值,从迭代器读取所有的值,然后按照返回顺序将他们依次插入到数组中。
*/
let map = new Map([["name", "song"], ["abc", "24"]]);
array = [...map];
console.log(array);