likes
comments
collection
share

js核心之Iterator迭代器

作者站长头像
站长
· 阅读数 23

先有问题再有答案

  1. js中的iterator是什么?
  2. 为什么需要iterator?
  3. iterator&js中的数据结构有什么关系?
  4. js的迭代器与设计模式中的迭代器模式有什么关系?
  5. iterator有哪些应用场景?
  6. 迭代 枚举 遍历 傻傻分不清?

iterator是什么?

定义:

在 ES6 中,迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一访问的机制。一个数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)

核心点

迭代器是一种接口 , 是为数据结构服务的

设计目的

一: 是为各种数据结构,提供一个统一的、简便的访问接口; 二: 是使得数据结构的成员能够按某种次序排列; 三: ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

协议内容

js核心之Iterator迭代器 任何实现了这个协议的对象都是迭代器对象 其结构如下:

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)接口。

js核心之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中的迭代器更具有语言特性,便于与其他语言特性结合使用。而设计模式中的迭代器模式则更强调通用概念,在很多其他编程语言中也可以找到类似的实现。

应用场景

  1. for...of循环:这种循环语句可以用来遍历任何实现了迭代器接口的对象。在每次循环中,它会自动调用迭代器的next()方法取出下一个元素。
  2. 扩展运算符(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} // 这个可以正常执行
  1. 解构赋值:对于实现了迭代器接口的集合,你可以用解构赋值的方式给变量赋值。
let [x, y] = new Set(['a', 'b']); 
console.log(x); // "a"
  1. 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
评论
请登录