記事ディレクトリ
序文
JavaScript 本来の「コレクション」を表すデータ構造は主に配列(Array
)とオブジェクト(Object
)ですが、ES6 では と が追加されましMap
たSet
。ユーザーはこれらを組み合わせて使用して独自のデータ構造を定義することもできます。たとえば、配列のメンバーは object でありMap
、Map
配列のメンバーはオブジェクトです。これには、さまざまなデータ構造をすべて処理するための統一されたインターフェイス メカニズムが必要です。
1. イテレータの概要
イテレータとはそのような仕組みです。これは、さまざまなデータ構造に対する統合アクセス メカニズムを提供するインターフェイスです。データ構造が Iterator インターフェイスをデプロイしている限り、トラバーサル操作を完了できます (つまり、データ構造のすべてのメンバーを順番に処理します)。
Iterator には 3 つの機能があります: 1 つはさまざまなデータ構造に統一された便利なアクセス インターフェイスを提供すること、もう 1 つはデータ構造のメンバーを特定の順序で配置できるようにすること、3 つ目は ES6 が新しいトラバーサル コマンド ループを作成することですfor...of
。 , Iterator インターフェイスは主にfor...of
消費用です。
2、反復子の原則
Iterator の直訳は、任意の反復可能なデータ型のデータを反復処理できる反復子であり、データを反復処理できる反復可能データのインターフェイス メカニズムを提供します。
一般に、関数の next メソッドを使用してデータを反復し、データが存在する場合はオブジェクトを返します{value :数据, done : false}
。
「データがありません」という場合は、オブジェクトを返します。{value : undefined , done : true}
したがって、反復子を使用する前に、データが反復を開始する場所を指すポインターを定義する必要があります。初期ポインターは 0 番目の要素を指します。
次の場合のように:
function makeIterator(array) {
var nextIndex = 0;
return {
// 注意:此处使用了闭包,nextIndex会被一直引用,也就是会被下面一直累加;
next: function() {
// 注意:此处判断结束条件 当前长度是否小于数组的总长度
// 小于说明未运行结束 不小于说明改结束了
return nextIndex < array.length ?
{
value: array[nextIndex++], done: false} :
{
value: undefined, done: true};
}
};
}
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
Iterator の走査プロセスは次のとおりです。
(1) 現在のデータ構造の開始位置を指すポインター オブジェクトを作成します。言い換えれば、トラバーサー オブジェクトは本質的にはポインター オブジェクトです。
(2) ポインター オブジェクトのメソッドが初めて呼び出されnext
、ポインターはデータ構造の最初のメンバーを指すことができます。
(3) ポインター オブジェクトのメソッドが 2 回目に呼び出されるときnext
、ポインターはデータ構造の 2 番目のメンバーを指します。
(4)next
データ構造の終端を指すまでポインタ オブジェクトのメソッドを呼び出し続けます。
next
メソッドが呼び出されるたびに、データ構造の現在のメンバーに関する情報が返されます。value
具体的には、と2 つのプロパティを含むオブジェクトを返しますdone
。このうち、value
属性は現在のメンバーの値であり、done
属性は走査が終了したかどうかを示すブール値です。
3. Iterator インターフェイスを実装するネイティブ オブジェクトは次のとおりです。
ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティにデプロイされることが規定されています。つまり、データ構造に Symbol.iterator プロパティがある限り、データ構造は通過可能であると見なされます。
Iterator インターフェイスをネイティブに持つデータ構造は次のとおりです。
- 配列
- 地図
- セット
- 弦
- 型付き配列
- 関数の引数オブジェクト
- NodeList オブジェクト
Array プロトタイプ オブジェクトと Set コレクションに Iterator プロパティが実装されていることがわかります。
// 数组
console.log("array:",Array.prototype);
// Es6新增Set集合
let set = new Set([1, 2, 3]);
console.log("set:",set);
次の図を出力します。
すると、次のように、配列のインスタンス オブジェクトにも当然このプロパティが設定されます。
let arrIter = [1, 2, 3][Symbol.iterator]();
console.log("arrIter:", arrIter);
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
console.log(arrIter.next());
5. Iteratorインターフェースがデフォルトで呼び出される場合
場合によっては、Iterator インターフェイス (つまり、メソッド) がデフォルトで呼び出されます。Symbol.iterator
以下で説明するfor...of
ループに加えて、他にもいくつかの場合があります。
(1) 代入の分割
配列および Set 構造体への代入を分割する場合、Symbol.iterator
デフォルトでこのメソッドが呼び出されます。
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
(2) スプレッド演算子
スプレッド演算子 (…) もデフォルトの Iterator インターフェイスを呼び出します。
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
実際、これは、Iterator インターフェイスを実装するデータ構造を配列に変換する便利なメカニズムを提供します。つまり、データ構造が Iterator インターフェイスを実装している限り、スプレッド演算子を使用して配列に変換できます。
let arr = [...iterable];
(3)収量*
yield*
続いてトラバース可能な構造体が続き、その構造体のトラバーサー インターフェイスが呼び出されます。
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
(4) その他の機会
配列のトラバーサルはトラバーサー インターフェイスを呼び出すため、配列をパラメーターとして受け入れる場合は実際にトラバーサー インターフェイスを呼び出します。以下にいくつかの例を示します。
- の
- Array.from()
- Map()、Set()、WeakMap()、WeakSet() (例
new Map([['a',1],['b',2]])
) - Promise.all()
- Promise.race()
ループの 6、for...
for... of循环其实就是 Iterator 的语法糖
for...of ループが使用できるスコープには、配列、Set および Map 構造体、一部の配列のようなオブジェクト (引数オブジェクト、DOM NodeList オブジェクトなど)、文字列などが含まれます。つまり、Iterator インターフェイスを持つデータ型は for ...of; によってトラバースできます。
(一般的なオブジェクトは走査できず、エラーが直接報告されます。obj は反復可能ではありません)
配列にはネイティブに反復子インターフェイスがあり (Symbol.iterator プロパティがデフォルトでデプロイされます)、for...of 循环本质上
これはこのインターフェイスを呼び出すことによって生成されるトラバーサーです。
for...of は次のように使用されます。
## 1,遍历数组
let arr = [{
name:'Eula',age:20},{
name:'Kaya',age:20}]
for (const iterator of arr) {
console.log("iterator:",iterator); // {name: 'Eula', age: 20} {name: 'Kaya', age: 20}
}
## 2,遍历字符串
let str = "hello"
for (const iterator of str) {
console.log("iterator:",iterator); // 'h' 'e' 'l'' l'' o'
}
## 3,遍历set集合
let set = new Set([{
name:'Eula',age:20},{
name:'Kaya',age:20}])
for (const iterator of set) {
console.log("iterator:",iterator); // {name: 'Eula', age: 20} {name: 'Kaya', age: 20}
}
## 4,遍历map集合
let map = new Map()
map.set('name','Eula')
map.set('age','18')
console.log("map:",map); // Map(2) {'name' => 'Eula', 'age' => '18'}
for (const iterator of map) {
console.log("iterator:",iterator); // ['name', 'Eula'] ['age', '18']
}
通常のオブジェクトを反復処理する場合は、for in ループを使用できます。
let obj = {
name:'Eula'}
for (const iterator in obj) {
console.log("键:",iterator); // name
console.log("值:",obj[iterator]); // Eula
}
七、概要
- データ構造のプロトタイプに属性がある限り
Symbol.iterator
、それは走査可能であるとみなされます。 - for...of ループは実際には Iterator の糖衣構文です。