ホームページ  >  記事  >  ウェブフロントエンド  >  イテレータは、データ コレクションにアクセスするための統一インターフェイス メソッドです。

イテレータは、データ コレクションにアクセスするための統一インターフェイス メソッドです。

不言
不言オリジナル
2018-07-20 10:15:321760ブラウズ

この記事では、Iterator によるデータ収集にアクセスするための統一インターフェイス方法を紹介します。必要な場合は、それを参照してください。

はじめに

Traverser Iterator は、データ コレクションにアクセスするために ES6 によって提供される統合インターフェイスです。トラバーサー インターフェイスが内部に展開されているデータ コレクションの場合、ユーザーは同じ方法で対応するデータ構造を取得できます。最新バージョンの Chrome ブラウザを使用している場合は、私たちがよく知っているミス・アレイが、彼女の心に届く別の道を静かに開いたことを知っておく必要があります。 Iterator是ES6为访问数据集合提供的统一接口。任何内部部署了遍历器接口的数据集合,对于用户来说,都可以使用相同方式获取到相应的数据结构。如果使用的是最新版Chrome浏览器,那么你要知道——我们所熟悉的数组小姐,已悄悄的打开了另一扇可抵达她心扉的小径。

1 正题

某个数据集合部署了Iterator接口,是指其Symbol.iterator属性指向一个能返回Iterator接口的函数。任何默认使用遍历器访问数据集合的方法,都会调用此属性以得到遍历器对象,再按照设定的顺序依次访问该数据结构的成员(关于Symbol.iterator请看最后一节的延伸阅读)。比如原生数组的遍历器为[][Symbol.iterator],也可以直接通过其构造函数的原型获取Array.prototype[Symbol.iterator]

1.1 基本行为

调用Iterator接口会返回一个新的遍历器对象(指针对象)。  
对象中必然有next方法,用于访问下一个数据成员。指针初始时指向当前数据结构的起始位置。

第一次调用对象的next方法,指针指向数据结构的第一个成员。  
第二次调用对象的next方法,指针指向数据结构的第二个成员。  
不断的调用对象的next方法,直到它指向数据结构的结束位置。

每次调用next方法,都会返回相同的数据结构:{ value, done }。  
其中value表示当前指向成员的值,没有则为undefined。  
其中done是一个布尔值,表示遍历是否结束,结束为true,否则false

遍历器接口的标准十分简洁,不提供诸如:操作内部指针、判断是否有值等等方法。只需要一直不断的调用next方法,当donefalse时获取当时的valuedonetrue时停止即可。第一次接触遍历器的行为模式是在2016的冬天,那时底蕴不够鸡毛也没长全,理解不了简洁性的适用和强大。直到现在——在即将打包被迫离开公司的前夕才蓦然的醒觉。多么痛的领悟啊。

let iterator = [1, 2, 3][Symbol.iterator]();

console.log( iterator.next() ); // {value: 1, done: false}
console.log( iterator.next() ); // {value: 2, done: false}
console.log( iterator.next() ); // {value: 3, done: false}
console.log( iterator.next() ); // {value: undefined, done: true}

1.2 简单实现

面向不同的数据结构,有不同的遍历器实现方法,我们简单的实现下数组的遍历器方法。

let res = null;
let iterator = myIterator([3, 7]);

console.log( iterator.next() ); // {value: 3, done: false}
console.log( iterator.next() ); // {value: 7, done: false}
console.log( iterator.next() ); // {value: undefined, done: true}

function myIterator(array = []) {
  let index = 0;
  return {
    next() {
      return index < array.length 
        ? { value: array[index++], done: false }
        : { value: undefined, done: true };
    }
  };
}

1.3 return & throw

除了为遍历器对象部署next方法,还可以有returnthrow方法。其中return方法会在提前退出for of循环时(通常是因为出错,或触发了break语句)被调用。而throw方法主要是配合Generator函数使用,一般的遍历器对象用不到这个方法,所以不予介绍。

let obj = {
  [Symbol.iterator]() {
    let index = 0;
    let array = [1, 2, 3];

    return {
      next() {
        return index < array.length 
          ? { value: array[index++], done: false }
          : { value: undefined, done: true };
      },
      return() {
        console.log(&#39;Trigger return.&#39;);
        return {};
      }
    };
  }
};

for (let v of obj) {
  console.log(v); // 打印出:1, 2, 3,没触发 return 函数。
}

for (let v of obj) {
  if (v === 2) break;
  console.log(v); // 打印出:1,之后触发 return 函数。
}

for (let v of obj) {
  if (v === 3) break;
  console.log(v); // 打印出:1, 2,之后触发 return 函数。
}

for (let v of obj) {
  if (v === 4) break;
  console.log(v); // 打印出:1, 2, 3,没触发 return 函数。
}

for (let v of obj) {
  if (v === 2) throw Error(&#39;error&#39;);
  console.log(v); // 打印出:1,之后触发 return 函数,并报错停止执行。
}

2 原生支持

2.1 默认持有遍历器

原生默认持有遍历器接口的数据结构有:
基本类型:Array, Set, Map(四种基本数据集合:Array, Object, SetMap)。
类数组对象:arguments, NodeList, String

let iterator = &#39;123&#39;[Symbol.iterator]();

console.log( iterator.next() ); // {value: "1", done: false}
console.log( iterator.next() ); // {value: "2", done: false}
console.log( iterator.next() ); // {value: "3", done: false}
console.log( iterator.next() ); // {value: undefined, done: true}

遍历器与先前的遍历方法
一个数据集合拥有遍历器接口,并不意味着所有遍历它的方法都是使用此接口。实际上,只有ES6新增的几种方式和某些方法会使用,下面会有介绍。以数组来说,对其使用forfor of虽然可访问到相同的成员,但是实际的操作方式却不同。

// 改变数组默认的遍历器接口。
Array.prototype[Symbol.iterator] = function () {
  let index = 0;
  let array = this;

  console.log(&#39;Use iterator&#39;);

  return {
    next() {
      return index < array.length 
        ? { value: array[index++], done: false }
        : { value: undefined, done: true };
    }
  }
};

let arr = [1, 2];

for (let v of arr) {
  console.log(v); // 打印出 Use iterator, 1, 2。
}

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]); // 打印出 1, 2。
}

arr.forEach(d => {
  console.log(d); // 打印出 1, 2。
});

对象没有默认的遍历器接口  
为什么对象没有默认的遍历器接口?这要从两方面说明。一为遍历器是种线性处理结构,对于任何非线性的数据结构,部署了遍历器接口,就等于部署一种线性转换。二是对象本来就是一个无序的集合,如果希望其有序,可以使用Map

1 メイントピック🎜🎜 特定のデータ コレクションは Iterator インターフェイスをデプロイします。これは、その Symbol.iterator 属性が を返すことができるデータ セットを指すことを意味します。イテレータ 関数。デフォルトでトラバーサーを使用してデータ コレクションにアクセスするメソッドは、このプロパティを呼び出してトラバーサー オブジェクトを取得し、設定された順序でデータ構造のメンバーにアクセスします (Symbol.iterator については最後のセクションを参照してください)。詳細については「code>」セクションを参照してください)。たとえば、ネイティブ配列のイテレータは <code>[][Symbol.iterator] です。または、そのプロトタイプから直接 Array.prototype[Symbol.iterator] を取得できます。コンストラクタ。 🎜

1.1 基本動作

🎜 Iterator インターフェイスを呼び出すと、新しいイテレータ オブジェクト (ポインタ オブジェクト) が返されます。
オブジェクトには、次のデータ メンバーにアクセスするために使用される next メソッドが必要です。ポインタは最初は現在のデータ構造の先頭を指します。 🎜🎜オブジェクトの next メソッドが初めて呼び出されるとき、ポインターはデータ構造の最初のメンバーを指します。
オブジェクトの next メソッドが 2 回目に呼び出されるとき、ポインタはデータ構造の 2 番目のメンバーを指します。
データ構造の終わりを指すまで、オブジェクトの next メソッドを繰り返し呼び出します。 🎜🎜 next メソッドが呼び出されるたびに、同じデータ構造、{ value, none } が返されます。
ここで、value は現在メンバーを指している値を表します。そうでない場合は、未定義となります。
done はブール値で、終了が true かどうかを示し、それ以外の場合は false です。 🎜🎜トラバーサーインターフェースの規格は非常にシンプルで、内部ポインターの操作や値の有無の判定などのメソッドは提供されていません。 next メソッドを呼び出し続け、donefalse になったら、現在の value を取得します。完了したら停止はtrueです。私がトラバーサーの行動パターンに初めて触れたのは、2016 年の冬でした。当時、私にはシンプルさの応用可能性と威力を理解するための十分な知識がありませんでした。突然目が覚めたのは、今まさに荷物をまとめて会社を去らなければならない直前のことだった。なんという痛ましい認識だろう。 🎜
let obj = {
  0: 'a',
  1: 'b',
  length: 2,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};

let iterator = obj[Symbol.iterator]();
console.log( iterator.next() ); // {value: "a", done: false}
console.log( iterator.next() ); // {value: "b", done: false}
console.log( iterator.next() ); // {value: undefined, done: true}

1.2 簡単な実装

🎜 データ構造ごとに異なるトラバーサー実装メソッドがあります。単純に配列トラバーサー メソッドを実装します。 🎜
let obj = {
  0: 'a',
  1: 'b',
  length: 2,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};

console.log( Object.keys(obj) ); // ["0", "1", "length"]

for (let v of obj) {
  console.log(v); // 依次打印出:"a", "b"。
}

for (let k in obj) {
  console.log(k); // 依次打印出:"0", "1", "length"。
}

1.3 return & throw

🎜 トラバーサー オブジェクトの next メソッドをデプロイすることに加えて、returnthrow も使用できます。 メソッド。 return メソッドは、for of ループを早期に終了するときに (通常はエラーまたは break ステートメントのトリガーにより) 呼び出されます。 throw メソッドは主に Generator 関数と組み合わせて使用​​されます。このメソッドは一般的なトラバーサー オブジェクトでは使用されないため、紹介されません。 🎜
for (let v of [1, 2, 3])  {
  console.log(v); // 依次打印出:1, 2, 3。
}
🎜2 ネイティブ サポート🎜

2.1 デフォルトでトラバーサーを保持します

🎜 デフォルトでトラバーサー インターフェイスを保持するデータ構造は次のとおりです:
基本タイプ: Array、 >Set、Map (4 つの基本データ コレクション: ArrayObjectSet >マップコード>)。 <br>配列のようなオブジェクト: <code>argumentsNodeListString。 🎜
let [...a] = [3, 2, 1]; // [3, 2, 1]
let b = [...[3, 2, 1]]; // [3, 2, 1]
🎜トラバーサーと以前のトラバーサル メソッド
データ コレクションにトラバーサー インターフェイスがあるからといって、データ コレクションを走査するすべてのメソッドがこのインターフェイスを使用するとは限りません。実際には、いくつかの新しいメソッドと、ES6 で追加された特定のメソッドのみが使用されます。これらについては、以下で紹介します。配列の場合、forfor of を使用すると同じメンバーにアクセスできますが、実際の操作は異なります。 🎜
for (let v of G()) {
  console.log(v); // 依次打印出:1, 2, 3, 4, 5
}

function* G() {
  yield 1;
  yield* [2,3,4];
  yield 5;
}
🎜オブジェクトにはデフォルトのトラバーサー インターフェイスがありません
オブジェクトにはデフォルトのトラバーサー インターフェイスがないのはなぜですか?これは 2 つの側面から説明する必要があります。まず、トラバーサーは線形処理構造です。非線形データ構造の場合、トラバーサー インターフェイスの展開は線形変換の展開と同じです。次に、オブジェクトは元々順序付けされていないコレクションです。順序付けしたい場合は、代わりに Map を使用できます。これは、誰もが独自の強みを持ち、誰もが独自の義務を負っていることを意味します。フンコロガシがフン玉を転がさずに蜂蜜を集めに行ったら、花売り娘は苦しむかもしれません。 🎜

自行生成的类数组对象(拥有length属性),不具备遍历器接口。这与String等原生类数组对象不同,毕竟人家是亲生的,一出生就含着金钥匙(也不怕误吞)。不过我们可以将数组的遍历器接口直接应用于自行生成的类数组对象,简单有效无副作用。

let obj = {
  0: 'a',
  1: 'b',
  length: 2,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};

let iterator = obj[Symbol.iterator]();
console.log( iterator.next() ); // {value: "a", done: false}
console.log( iterator.next() ); // {value: "b", done: false}
console.log( iterator.next() ); // {value: undefined, done: true}

为对象添加遍历器接口,也不影响之前不使用遍历器的方法,比如for in, Object.keys等等(两者不等同)。

let obj = {
  0: 'a',
  1: 'b',
  length: 2,
  [Symbol.iterator]: Array.prototype[Symbol.iterator]
};

console.log( Object.keys(obj) ); // ["0", "1", "length"]

for (let v of obj) {
  console.log(v); // 依次打印出:"a", "b"。
}

for (let k in obj) {
  console.log(k); // 依次打印出:"0", "1", "length"。
}

2.2 默认调用遍历器

for of  
for of是专门用来消费遍历器的,其遍历的是键值(for in遍历的是键名)。

for (let v of [1, 2, 3])  {
  console.log(v); // 依次打印出:1, 2, 3。
}

扩展运算符  
无论是解构赋值或扩展运算都是默认调用遍历器的。

let [...a] = [3, 2, 1]; // [3, 2, 1]
let b = [...[3, 2, 1]]; // [3, 2, 1]

yield*  
Generator函数中有yield*命令,如果其后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。

for (let v of G()) {
  console.log(v); // 依次打印出:1, 2, 3, 4, 5
}

function* G() {
  yield 1;
  yield* [2,3,4];
  yield 5;
}

其它场合  
有些接受数组作为参数的函数,会默认使用数组的遍历器接口,所以也等同于默认调用。比如Array.from(), Promise.all()

相关推荐:

angularjs关于页面模板清除的使用方法

在JS中用slice封装数组方法

以上がイテレータは、データ コレクションにアクセスするための統一インターフェイス メソッドです。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。