Skip to content

Commit

Permalink
add: 将自定义类封装为可迭代对象
Browse files Browse the repository at this point in the history
  • Loading branch information
qianguyihao committed May 27, 2023
1 parent ba2a958 commit ef7f9ca
Showing 1 changed file with 125 additions and 81 deletions.
206 changes: 125 additions & 81 deletions 07-JavaScript进阶/03-迭代器和生成器.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ console.log(JSON.stringify(strArrIterator.next()));

### 可迭代对象的特征

上面的代码中,我们将 myObj2 数据对象封装成了可迭代对象。凡是可迭代对象,都具备如下特征:
凡是可迭代对象,都具备如下特征:

1、可迭代对象都有一个 [Symbol.iterator] 函数。通过这个函数,我们可以进行一些数据遍历操作。以一个简单的数组进行举例:
1、可迭代对象都有一个 [Symbol.iterator] 函数。通过这个函数,我们可以进行数据遍历操作。以一个简单的数组进行举例:

```js
const myArr = ['qian', 'gu', 'yi', 'hao'];
Expand Down Expand Up @@ -145,9 +145,99 @@ yi
hao
```

### 为普通对象创建迭代器
### 原生可迭代对象

以下这些对象,都是原生可迭代对象,请务必记住:

- String 字符串
- Array 数组
- Map
- Set
- arguments 对象
- NodeList 对象(DOM节点的集合)

原生可迭代对象的内部已经实现了可迭代协议,它们都符合可迭代对象的特征。比如,它们内部都有一个迭代器;他们可以用 for ... of 进行遍历。

为何要记住上面这些可迭代对象,因为可迭代对象的应用场景非常多,且非常好用。我们继续往下学习。

### 可迭代对象的应用场景(重要)

可迭代对象有许多应用场景,包括但不仅限于:

1、JavaScript的语法:

- for ... of
- 展开语法 ...
- yield*
- 解构赋值

2、创建一些对象:

- new Map([Iterable]):参数是可选的,可不传参数,也可以传一个可迭代对象作为参数
- new WeakMap([iterable])
- new Set([iterable])
- new WeakSet([iterable])

3、方法调用

- Array.from(iterable):将一个可迭代对象转为数组
- Promise.all(iterable)
- Promise.race(iterable)

今后在遇到这些应用场景时,这些原生可迭代对象可以直接拿来用。

比如说,通过阅读官方文档后我们得知,`new Set()`的写法中,括号里的参数可以不写,也可以传入一个可迭代对象 `iterable`。那么,字符串、数组、Set、Map等可迭代对象,在你需要的时候都可以传进去使用。而且,`const a = new Set()`写法中,变量 a 也是一个可迭代对象。

`Promise.all(iterable)` 只能传数组吗?非也。准确来说,Promise.all()的参数中,传入的不是数组,而是一个可迭代对象。代码举例:

```js
const promise1 = Promise.resolve('promise1 resolve');
const promise2 = Promise.resolve('promise2 resolve');
const promise3 = Promise.resolve('promise3 resolve');

const promiseSet = new Set();
promiseSet.add(promise1);
promiseSet.add(promise2);
promiseSet.add(promise3);

// 准确来说,Promise.all()的参数中,传入的不是数组,而是一个可迭代对象
Promise.all(promiseSet).then(res => {
console.log('res:', res);
});
```

代码举例:

```
res: ['promise1 resolve', 'promise2 resolve', 'promise3 resolve']
```

arguments 同样是一个可迭代对象,但不是数组。我们可以通过`Array.from(iterable)`方法将 arguments 转为数组,进而让其享受数组的待遇,调用数组的各种方法。代码举例:

```js
foo('a', 'b', 'c');

// 定义函数
function foo() {
// Array.from() 中的参数可以传入可迭代对象,将参数转为数组。arguments 是 foo() 函数的参数
const arr = Array.from(arguments);
console.log(arr);
}
```

打印结果:

```
['a', 'b', 'c']
```

学完了迭代器、可迭代对象的知识之后,很多关于函数传参、数据遍历、数据结构等方面的JS知识,就能融会贯通了。

## 手写迭代器

现在有下面这两个对象,我们想为其创建迭代器
很多数据对象由于不是可迭代对象,我们可以为其手动创建一个迭代器,这个数据对象就成了可迭代对象。

### 为普通对象创建迭代器

代码举例:(这段代码和上一段代码比较类似)

Expand Down Expand Up @@ -187,7 +277,7 @@ console.log(strArrIterator.next());

### 将普通对象封装为可迭代对象

上面的数据 myObj1,不属于可迭代对象,因此我们单独写了一个迭代器 strArrIterator 对象,这两个对象是分开的
上面的数据 myObj1,不属于可迭代对象,因此我们单独写了一个迭代器对象 strArrIterator。但是这两个对象是分开的

还有一种更高级的做法是,把迭代器封装到数据对象的内部。完事之后,这个数据对象就是妥妥的可迭代对象。

Expand Down Expand Up @@ -335,96 +425,50 @@ name qianguyihao
skill web
```

### 原生可迭代对象

以下这些对象,都是原生可迭代对象,请务必记住:

- String 字符串
- Array 数组
- Map
- Set
- arguments 对象
- NodeList 对象(DOM节点的集合)

原生可迭代对象的内部已经实现了可迭代协议,它们都符合可迭代对象的特征。比如,它们内部都有一个迭代器;他们可以用 for ... of 进行遍历。

为何要记住上面这些可迭代对象,因为可迭代对象的应用场景非常多,且非常好用。我们继续往下学习。

## 可迭代对象的应用场景

可迭代对象有许多应用场景,包括但不仅限于:

1、JavaScript的语法:

- for ... of
- 展开语法 ...
- yield*
- 解构赋值

2、创建一些对象:

- new Map([Iterable]):参数是可选的,可不传参数,也可以传一个可迭代对象作为参数
- new WeakMap([iterable])
- new Set([iterable])
- new WeakSet([iterable])

3、方法调用

- Array.from(iterable):将一个可迭代对象转为数组
- Promise.all(iterable)
- Promise.race(iterable)

今后在遇到这些应用场景时,这些原生可迭代对象可以直接拿来用。

比如说,通过阅读官方文档后我们得知,`new Set()`的写法中,括号里的参数可以不写,也可以传入一个可迭代对象 `iterable`。那么,字符串、数组、Set、Map等可迭代对象,在你需要的时候都可以传进去使用。而且,`const a = new Set()`写法中,变量 a 也是一个可迭代对象。

`Promise.all(iterable)` 只能传数组吗?非也。准确来说,Promise.all()的参数中,传入的不是数组,而是一个可迭代对象。代码举例:

```js
const promise1 = Promise.resolve('promise1 resolve');
const promise2 = Promise.resolve('promise2 resolve');
const promise3 = Promise.resolve('promise3 resolve');

const promiseSet = new Set();
promiseSet.add(promise1);
promiseSet.add(promise2);
promiseSet.add(promise3);

// 准确来说,Promise.all()的参数中,传入的不是数组,而是一个可迭代对象
Promise.all(promiseSet).then(res => {
console.log('res:', res);
});
```
### 将自定义类封装为可迭代对象

代码举例:

```
res: ['promise1 resolve', 'promise2 resolve', 'promise3 resolve']
```
```json
// 定义类
class Person {
constructor(name, arr) {
this.name = name;
this.arr = arr;
}

arguments 同样是一个可迭代对象,但不是数组。我们可以通过`Array.from(iterable)`方法将 arguments 转为数组,进而让其享受数组的待遇,调用数组的各种方法。代码举例:
// 定义一个名为 [Symbol.iterator] 的实例方法,封装迭代器
[Symbol.iterator]() {
let index = 0;
const iterator = {
next: () => {
if (index < this.arr.length) {
return { done: false, value: this.arr[index++] };
} else {
return { done: true };
}
},
};
return iterator;
}
}

```js
foo('a', 'b', 'c');
const person1 = new Person('千古壹号', ['前端', '工程师']);
const person2 = new Person('许嵩', ['想象之中', '有何不可']);

// 定义函数
function foo() {
// Array.from() 中的参数可以传入可迭代对象,将参数转为数组。arguments 是 foo() 函数的参数
const arr = Array.from(arguments);
console.log(arr);
// Person的实例已经封装为可迭代兑现了,可以通过 for ... of 进行遍历
for (const item of person2) {
console.log(item);
}
```

打印结果:

```
['a', 'b', 'c']
想象之中
有何不可
```

学完了迭代器、可迭代对象的知识之后,很多关于函数传参、数据遍历、数据结构等方面的JS知识,就能融会贯通了。






Expand Down

0 comments on commit ef7f9ca

Please sign in to comment.