遍历器 iterator
iterator 遍历器对象
什么是遍历器对象?
遍历器也叫做迭代器。
iterator(遍历器对象)是一种接口,为各种不同的数据提供统一的访问机制,任何数据只要部署了 iterator 接口就可以进行遍历操作。
遍历器对象:数据类型是Object。
js
数组,(string,Set,Map,argument,HTMLcollection,NodelistCollection等数据类型)本身不是遍历器,但是数组中包含了遍历器对象(接口),当使用遍历器对象时,就可以直接使用。
遍历器对象的特点?
Next内置方法
js
[].next();
js
1. 每个遍历器都有一个 next() 方法
2. 遍历器对象内部存在一个指针,初始指向遍历器对象中的第一个数据,调用 next() 会取出当前指针指向的数据,并且指针下移。
3. 每次调用 next() 方法,返回对象,对象中包含 value 属性 和 done 属性, value 属性就是当前指针指向的数据的值,done 属性是一个布尔值,有没有指向空,表示是否结束遍历。
得到遍历器对象的方法:
js
数组实例: keys() values() entries()
Set实例: keys() values() entries()
Map实例: keys() values() entries()
...
遍历器对象案例
js
// 创建数组
const arr = [100,200,300,400,500,600,700];
// 获取由数组arr中的值组成的遍历器对象
const valIter = arr.values();
console.log(valIter);
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log(valIter.next());
console.log('');
console.log('');
// 获取由数组arr中的key组成的遍历器对象
const keyIter = arr.keys();
console.log(keyIter);
while (true) {
let data = keyIter.next();
if (data.done) {
break;
}
console.log(data.value);
}
console.log('');
console.log('');
// 获取由数组arr中的键值对组成的遍历器
const kvIter = arr.entries();
console.log(kvIter);
//
// 使用 for of 结构遍历遍历器对象 console.log(kvIter.next());
for (let v of kvIter) {
console.log(v);
}
// console.log(kvIter.next());
遍历遍历器对象 for of
js
使用for of 遍历遍历器对象
const kvIter = arr.entries();
console.log(kvIter);
for(let v of kvIter){
console.log(v); //这里的v是遍历器对象每次遍历得到一个元素,相当于调用了next()方法
}
iterable 可遍历对象
① 什么是可遍历对象
js
1. 把部署了 iterator 接口(遍历器接口)的数据类型称为 iterable (可遍历对象)
2. iterator 接口部署在了可遍历对象的 Symbol.iterator 属性上,该属性是一个方法,这个方法返回一个遍历器对象
js
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1,
done: true
};
}
};
}
};
js
// 创建数组
const arr = [100,200,300,400,500];
const msg = 'Hello World';
const set = new Set(msg);
console.log(arr);
console.log(msg);
console.log(set);
console.log('');
// 调用数组的 iterator 接口,可以得到一个遍历器
const iter = arr[Symbol.iterator]();
console.log(iter);
console.log(iter.next());
console.log('');
for (let v of arr) {
console.log(v);
}
console.log('');
for (let v of msg) {
console.log(v);
}
console.log('');
for (let s of set) {
console.log(s);
}
② 系统内置的可遍历对象
js
Array 的实例
Set 的实例
Map 的实例
字符串
arguments
NodeList
HTMLCollection
....
③ 哪些情况会调用可遍历对象的遍历器接口
调用可遍历对象的遍历器接口,目的就是为了拿到遍历器对象
js
1. 使用 for of 遍历可遍历对象
2. 数组的解构赋值,所有可遍历对象都可以被解构
3. Array.from() 该方法可以把可遍历对象转为数组
4. 使用扩展运算符将可遍历对象分割为逗号隔开的参数序列
5. Set 构造函数的参数,要求是可遍历对象
6. WeakSet 构造函数的参数,要求是可遍历对象
7. Map 构造函数的参数,要求是可遍历对象
9. WeakMap 构造函数的参数,要求是可遍历对象
9. Promise.all() 的参数
10. Promise.race() 的参数
....
④ 可遍历对象(iterable)和遍历器对象(iterator)的关系
js
1. 所有的遍历器对象都是可遍历的,可遍历对象不是遍历器对象。
2. 所有的可遍历对象都可以通过遍历器接口获取到与之对应的遍历器。
⑤ 可遍历对象(iterable)和伪数组的关系
js
1. 伪数组指的是像数组一样具有索引结构,由多个数据组成的不是数组的数据类型
2. 可遍历对象指的是部署了遍历器接口的对象
3. 二者是完全不同的两个概念, String、Arguments、NodeList、HTMLCollection 既是伪数组又是可遍历对象(ES5叫法); Set、Map 不是伪数组是可遍历对象(ES6)。
for ... of
js
所有的可遍历对象(包括遍历器对象)都可以使用 for of 进行遍历。
生成器 generator
什么是生成器
js
1. 能够创建遍历器的函数称为生成器函数(generator)
2. 可遍历对象的遍历器接口(Symbol.iterator 属性的值)方法就是一个生成器函数
如何自定义生成器
js
function* 生成器名字() {
}
js
// 创建生成器
function* gen() {
//console.log(1);
yield 100;
//console.log(2);
yield 200;
//console.log(3);
yield 300;
// return;
yield {name:'小乐'};
yield 500;
yield 600;
}
console.log(typeof gen); // function
// 调用生成器 得到遍历器对象
const iter = gen();
console.log(iter);
console.log('');
// console.log(iter.next());
// console.log(iter.next());
for (let v of iter) {
console.log(v);
}
// function func() {
// yield 100;
// }
yield 关键字
用于定义遍历器中的遍历元素
js
function* 生成器名字() {
yield 值;
yield 值;
yield 值;
yield 值;
yield 值;
}
js
1. yield 关键字只能在生成器函数中使用
2. 调用生成器函数得到遍历器对象之后,调用遍历器对象的next()方法,得到yield 后面的数据,作为next()返回对象的value属性的值
3. 调用生成器函数的时候,只会得到一个遍历器对象,不会执行生成器中的语句; 只有调用遍历器对象的 next()方法的时候,才会执行生成器中的语句,执行到 yield 会停下来,再调用 next() ,再执行到下一次 yield
4. 生成器中的 return,可以结束遍历器的遍历
利用生成器给对象部署 iterator 接口(自定义可遍历对象)
js
const obj = {
name: '高小乐',
age: 18,
address: '上海',
users: ['刘姥姥', '马姥姥', '欧阳姥姥', '司马姥姥'],
say: ()=>{}
};
// 给 obj 部署一个遍历器接口
obj[Symbol.iterator] = function*(){
//使用for in 遍历 Object对象,这里的this指向user对象,谁调用,指向谁
for (let i in obj) {
yield [i, this[i]];
}
};
// user 变成可便遍历对象
for (let v of user){ // for of 相当于调用了每次都调用 user.next()方法
console.log(v);
}
js
const user = {
name: '高小乐',
age: 18,
address: '上海',
users: ['刘姥姥', '马姥姥', '欧阳姥姥', '司马姥姥'],
say: ()=>{}
};
// 部署iterator接口 遍历user所有的属性
user[Symbol.iterator] = function* () {
for (let prop in this) {
yield [prop, this[prop]];
}
};
// user 变成了可遍历对象
for (let v of user) {
console.log(v);
}
console.log('');
console.log('');
//数组解构赋值
const [a1, a2, a3] = user;
console.log(a1);
console.log(a2);
console.log(a3);
console.log('');
console.log('');
//使用 扩展运算符 把 对象 象拆分为逗号隔开的键值对序列
console.log([...user]);
案例 深拷贝
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const user01 = {
name: '高小乐',
address: '上海',
children: ['司马姥姥', '欧阳姥姥', '东方姥姥'],
parent: {
name: '高育良',
age: 100,
address: '北京'
}
};
// 复制对象 user01
// const user02 = user01;
// 利用扩展运算符 实现复制 浅拷贝
const user02 = {...user01};
user02.name = '低大悲';
user02.children[2] = '西门姥姥';
console.log(user01);
console.log(typeof []);
console.log(typeof Array);
</script>
</body>
</html>