遍历器与迭代器

2023-07-04  本文已影响0人  Mr无愧于心

Iterator

任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。
Iterator 的作用有三个:

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

ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,或者说,一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)

Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环

let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }

生成一个Iterater

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++]} :
        {done: true};
    }
  };
}

对于普通的对象object,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用,主要因为object是没有顺序的。如果想遍历的话,Object.keys方法将对象的键名生成一个数组,然后遍历这个数组

for...of、for...in、forEach的区别
1. 不能遍历对象
2. 数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员
3. for...of循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如arguments对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串

遍历键值键名的方式
let arr = ['a', 'b', 'c'];
for (let pair of arr.entries()) {
  console.log(pair);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']

1. 数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
2. for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
3. for...in循环会以任意顺序遍历键名,适合遍历对象,不适合遍历数组
1. 无法中途跳出forEach循环,break命令或return命令都不能奏效

Generater

Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}
var hw = helloWorldGenerator();// 返回一个遍历器对象 (Iterator Object)
hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行(异步可中断,与react的机制相同,但是会引进新的副作用,所以没被react采用)。

function* gen(){
  // some code
}
var g = gen();
g[Symbol.iterator]() === g
// true

Generater的异步应用

  1. 回调函数
  2. 事件监听
  3. 发布/订阅
  4. Promise 对象
  5. Generater
  6. async...await
var fetch = require('node-fetch');
function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

var g = gen();
var result = g.next();

result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});
const Thunk = function(fn) {
  return function (...args) {
    return function (callback) {
      return fn.call(this, ...args, callback);
    }
  };
};
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);

基于 Thunk 函数的 Generator 执行器

function run(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next);
  }

  next();
}

function* g() {
  // ...
}

run(g);

CO模块自动执行

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(gen);
上一篇下一篇

猜你喜欢

热点阅读