js核心之Iterator迭代器
先有问题再有答案
js中的iterator是什么?
为什么需要iterator?
iterator&js中的数据结构有什么关系?
js的迭代器与设计模式中的迭代器模式有什么关系?
iterator有哪些应用场景?
迭代 枚举 遍历 傻傻分不清?
iterator是什么?
定义:
在 ES6 中,迭代器(Iterator)是一种接口
,为各种不同的数据结构
提供统一访问的机制。一个数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)
核心点
迭代器是一种接口
, 是为数据结构服务的
设计目的
一: 是为各种数据结构,提供一个统一的、简便的访问接口;
二: 是使得数据结构的成员能够按某种次序排列;
三: ES6 创造了一种新的遍历命令for...of
循环,Iterator 接口主要供for...of
消费。
协议内容
任何实现了这个协议的对象都是迭代器对象
其结构如下:
const obj = {
[Symbol.iterator] : function () {
return {
next: function () {
return {
value: 1, // 具体值
done: true // 是否遍历完成
};
}
};
}
};
iterator&数据结构
iterator是作用于数据结构的,在JavaScript中,部分内置数据结构已经默认实现了迭代器接口(Symbol.iterator),包括字符串(String)、数组(Array)、类数组对象、Map、Set、WeakMap和WeakSet等。这意味着这些数据结构的实例可以直接使用for...of或者扩展运算符进行遍历。
String
let str = "hello";
for (let char of str) {
console.log(char); // 依次打印 h e l l o
}
Array
let arr = [1, 2, 3];
for(let item of arr){
console.log(item); // 依次打印 1 2 3
}
类数组对象
const likeArray = document.getElementsByTagName('div');
const a = [...likeArray];
Array.isArray(likeArray) // false
Array.isArray(a) // true
Map、Set:直接部署了迭代器(Iterator)接口。
Object
let obj = {
a: 1,
b: 2,
c: 3
};
[...obj] // Uncaught TypeError: obj is not iterable
对象不支持迭代 这里通过与symbol + Generator函数配合实现了迭代的能力。
let obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function* () {
yield this.a;
yield this.b;
yield this.c;
}
};
[...obj] // [1, 2, 3]
或者可以利用数组的迭代能力
let obj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function(){
return Object.values(this)[Symbol.iterator]();
}
};
[...obj] // [1, 2, 3]
设计模式中的迭代器模式有什么关系
设计模式中的迭代器模式定义了一个迭代器接口,通常包括一个用于获取下一个元素的next()方法以及一个用于判断是否仍有更多元素的hasNext()方法。不同的数据结构可以实现该迭代器接口,为外部程序提供统一的遍历方法。
ES6中的迭代器提供了类似的功能。迭代器有一个next()方法,用于访问下一个元素,并返回一个包含value(当前访问的元素值)和done(指示迭代是否完成)的对象。ES6中的迭代器还引入了Symbol.iterator这一特性,使得任何实现了Symbol.iterator接口的对象都可以使用for...of循环和扩展运算符等。
设计模式中的迭代器模式和ES6中的迭代器都是为了提供统一的遍历方式和对内部实现的解耦。但在具体实现上,ES6中的迭代器更具有语言特性,便于与其他语言特性结合使用。而设计模式中的迭代器模式则更强调通用概念,在很多其他编程语言中也可以找到类似的实现。
应用场景
- for...of循环:这种循环语句可以用来遍历任何实现了迭代器接口的对象。在每次循环中,它会自动调用迭代器的next()方法取出下一个元素。
- 扩展运算符(Spread Operator)...:它可以将一个具有迭代器的集合转化为一个数组。
let set = new Set().add('a').add('b').add('c');
let arr = [...set];
console.log(arr); // ["a", "b", "c"]
这里会有些差异 当使用扩展运算符转化为数组时,会调用对象的迭代器转换; 当转化为对象时,是对目标对象可枚举属性的浅拷贝。
const obj = {
a: 1,
b: 2
}
{...obj} // 这个可以正常执行
- 解构赋值:对于实现了迭代器接口的集合,你可以用解构赋值的方式给变量赋值。
let [x, y] = new Set(['a', 'b']);
console.log(x); // "a"
- Array.from()方法:这个方法可以将两类对象转为真正的数组,其中包括类似数组的对象(有length属性和索引元素)和实现了迭代器接口的对象。
let arr1 = Array.from(new Set([1, 2, 3]));
console.log(arr1); // [1, 2, 3]
遍历对象的几种方式
可迭代对象
对于可迭代的数据结构我们可以使用迭代器遍历 例如上面提到的string,Array,likeArray, Map,Set等。
不可迭代的对象
例如Object 我们可以自己实现迭代器,但是一般不这么做,所以并不推荐。 js给我们提供了其他的遍历方式。
Object.keys(推荐)
Object.keys() 方法返回一个由对象的自身(不包括原型链)可枚举属性组成的数组。
let obj = {a: 1, b: 2};
Object.keys(obj).forEach(key => {
console.log(key); // 输出 'a' 'b'
});
Object.entries
这个方法返回一个给定对象自身可枚举属性的键值对数组。
let obj = {a: 1, b: 2};
Object.entries(obj).forEach(([key, value]) => {
console.log(key, value); // 输出 'a' 1 'b' 2
});
Object.getOwnPropertyNames
这个方法返回一个由对象的自身所有属性(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。
let obj = {a: 1, b: 2};
Object.getOwnPropertyNames(obj).forEach(key => {
console.log(key); // 输出 'a' 'b'
});
for..in循环
for...in 循环可以遍历出对象的所有可枚举的属性,包括原型链上的属性。
let obj = {a: 1, b: 2};
for(let key in obj) {
console.log(key); // 输出 'a' 'b'
}
迭代&遍历&枚举
遍历: 指的是访问数据结构的所有元素的过程, 遍历可以应用于任何类型的数据结构,包括数组、对象、树、图等
迭代: 在js中实现了迭代器接口的对象被称为可迭代的。迭代是遍历的一种情况
枚举: 对象的每个属性都有自己的属性描述符,可以配置属性是否可枚举,能否被遍历到,所以枚举一般修饰对象的某个属性。
相关文章
转载自:https://juejin.cn/post/7386916905008529423