Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js核心之Iterator迭代器 #68

Open
wuyunqiang opened this issue Jul 23, 2024 · 0 comments
Open

js核心之Iterator迭代器 #68

wuyunqiang opened this issue Jul 23, 2024 · 0 comments
Labels

Comments

@wuyunqiang
Copy link
Owner

先有问题再有答案

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

iterator是什么?

定义:

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

核心点

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

设计目的

一: 是为各种数据结构,提供一个统一的、简便的访问接口;

二: 是使得数据结构的成员能够按某种次序排列;

三: ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。

协议内容

截屏2024-07-02 下午4.42.50.png
任何实现了这个协议的对象都是迭代器对象

其结构如下:

const obj = {
  [Symbol.iterator] : function () {
    return {
      next: function () {
        return {
          value: 1, // 具体值
          done: true // 是否遍历完成
        };
      }
    };
  }
};

在js中主要是通过 Symbol.iterator生成器函数来完成的。

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

WeakMap、WeakSet 因为是弱引用内容随时会被删除,不支持迭代所以没有Iterator接口,具体参考 js基石之Object,Map,WeakMap

截屏2024-07-02 下午5.42.34.png

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中实现了迭代器接口的对象被称为可迭代的。迭代是遍历的一种情况

枚举: 对象的每个属性都有自己的属性描述符,可以配置属性是否可枚举,能否被遍历到,所以枚举一般修饰对象的某个属性。

相关文章

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant