この記事では主にES6イテレータ(Iterator)とfor.ofループの使い方の学習まとめを紹介しますので、参考にしてください。
1. イテレータとは何ですか?
ジェネレーターのコンセプトは Java、Python、その他の言語で利用でき、ES6 は JavaScript にも追加されました。 Iterator を使用すると、コレクション変数とインデックス変数を初期化する必要がなくなり、代わりに反復子オブジェクトの next メソッドを使用してコレクション内の次の項目の値を返します。これはプログラミングに特化しています。
イテレータは特別なインターフェイスを持つオブジェクトです。 next() メソッドが含まれます。この呼び出しは、value と Done という 2 つの属性を含むオブジェクトを返します。Value は現在の位置の値を表し、done が true の場合、next の呼び出しは無効になります。
ES5 のコレクションの走査は通常 for ループであり、配列にも forEach メソッドがあり、ES6 では Map と Set が追加され、イテレーターはすべてのコレクション データを統一的に処理できます。イテレータはインターフェイスです。データ構造がイテレータ インターフェイスを公開している限り、反復を完了できます。 ES6 では新しいトラバーサル コマンド for...of ループが作成され、Iterator インターフェイスは主に for...of による消費に使用されます。
2. イテレータの使い方
1. デフォルトのIteratorインターフェース
データ構造 Iteratorインターフェースがデプロイされている限り、このデータ構造は「Iterable」になります。 ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティに展開されることが規定されています。つまり、データ構造に Symbol.iterator データがある限り、それは「トラバース可能」(反復可能) であると見なされます。 ...of
これは、オブジェクト属性の走査順序が不確実であり、開発者が手動で指定する必要があるためです。本質的に、トラバーサーは線形プロセスです。非線形データ構造の場合、トラバーサー インターフェイスの展開は線形変換の展開と同じです。
// code1 function Obj(value) { this.value = value; this.next = null; } Obj.prototype[Symbol.iterator] = function() { var iterator = { next: next }; var current = this; function next() { if (current) { var value = current.value; current = current.next; return { done: false, value: value }; } else { return { done: true }; } } return iterator; } var one = new Obj(1); var two = new Obj(2); var three = new Obj(3); one.next = two; two.next = three; for (var i of one) { console.log(i); } // 1 // 2 // 3
(1) 代入の構造化
// code2 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) 演算子を展開// code3
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
// code4 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) その他の場合
for..of
// code5 myArray.forEach(function (value) { console.log(value); });
この書き方の問題点は、forEach ループを途中で抜け出すことができず、break コマンドも return コマンドも有効にならないことです。 オブジェクト for...in ループの欠点をもう一度見てください:
for (var index in myArray) { console.log(myArray[index]); };
配列のキー名は数字ですが、for...in ループではキー名として文字列「0」、「」が使用されます。 1 」、「2」など
for (var n of fibonacci) { if (n > 1000) { break; console.log(n); } }
for...of ループを使用すると、配列を走査してキー値を取得できますvar arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
console.log(a); // 0 1 2 3
}
for (let a of arr) {
console.log(a); // a b c d
}
let arr = [3, 5, 7]; arr.foo = 'hello'; for (let i in arr) { console.log(i); // "0", "1", "2", "foo" } for (let i of arr) { console.log(i); // "3", "5", "7" }
(2) Map 構造体と Set 構造体
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]); for (var e of engines) { console.log(e); } // Gecko // Trident // Webkit var es6 = new Map(); es6.set("edition", 6); es6.set("committee", "TC39"); es6.set("standard", "ECMA-262"); for (var [name, value] of es6) { console.log(name + ": " + value); } // edition: 6 // committee: TC39 // standard: ECMA-262
上記のコードから、for...of ループが Map 構造体と Set 構造体を走査するとき、走査の順序は各メンバーの順序であることがわかります。 Set 構造を走査すると値が返され、Map 構造を走査すると配列の 2 つのメンバーが返されます。マップメンバー。
(3) 配列状のオブジェクト
String
// 普通的字符串遍历 let str = "yuan"; for (let s of str) { console.log(s); // y u a n } // 遍历含有 32位 utf-16字符的字符串 for (let x of 'a\uD83D\uDC0A') { console.log(x); } // 'a' // '\uD83D\uDC0A'
DOM NodeList オブジェクト
let paras = document.querySelectorAll("p"); for (let p of paras) { p.classList.add("test"); }
arguments オブジェクト
function printArgs() { for (let x of arguments) { console.log(x); } } printArgs("a", "n"); // "a" // "n"
配列状のオブジェクトのトラバーサル処理用の Iterator インターフェースはありません
Array.from メソッドを借用して処理します
let arrayLike = { length: 2, 0 : 'a', 1 : 'b' }; // 报错 for (let x of arrayLike) { console.log(x); } // 正确 for (let x of Array.from(arrayLike)) { console.log(x); }
(4) オブジェクト
通常のオブジェクトの場合、for...of を直接使用してトラバースすることはできません。そうでない場合はエラーが報告され、これを使用するには Iterator インターフェイスをデプロイする必要があります。次の 2 つの方法でデプロイします:
// 方法一:使用 Object.keys 方法讲对象的键名生成一个数组 for (var key of Object.keys(someObject)) { console.log(key + ": " + someObject[key]); } // 方法二:使用Generator 函数将对象重新包装一下 function * entries(obj) { for (let key of Object.keys(obj)) { yield[key, obj[key]]; } } for (let[key, value] of entries(obj)) { console.log(key, "->", value); } // a -> 1 // b -> 2 // c -> 3
三、迭代器应用实例
1、斐波那契数列
下面我们就使用迭代器来自定义自己的一个斐波那契数列组,我们直到斐波那契数列有两个运行前提,第一个前提是初始化的前两个数字为0,1,第二个前提是将来的每一个值都是前两个值的和。这样我们的目标就是每次都迭代输出一个新的值。
var it = { [Symbol.iterator]() { return this }, n1: 0, n2: 1, next() { let temp1 = this.n1, temp2 = this.n2; [this.n1, this.n2] = [temp2, temp1 + temp2] return { value: temp1, done: false } } } for (var i = 0; i < 20; i++) { console.log(it.next()) } // "value": 0, "done": false } { "value": 1, "done": false } { "value": 1, "done": false } { "value": 2, "done": false } { "value": 3, "done": false } { "value": 5, "done": false }... { "value": 2584, "done": false } { "value": 4181, "done": false }
2、任务队列迭代器
我们可以定义一个任务队列,该队列初始化时为空,我们将待处理的任务传递后,传入数据进行处理。这样第一次传递的数据只会被任务1处理,第二次传递的只会被任务2处理… 代码如下:
var Task = { actions: [], [Symbol.iterator]() { var steps = this.actions.slice(); return { [Symbol.iterator]() { return this; }, next(...args) { if (steps.length > 0) { let res = steps.shift()(...args); return { value: res, done: false } } else { return { done: true } } } } } } Task.actions.push(function task1(...args) { console.log("任务一:相乘") return args.reduce(function(x, y) { return x * y }) }, function task2(...args) { console.log("任务二:相加") return args.reduce(function(x, y) { return x + y }) * 2 }, function task3(...args) { console.log("任务三:相减") return args.reduce(function(x, y) { return x - y }) }); var it = Task[Symbol.iterator](); console.log(it.next(10, 100, 2)); console.log(it.next(20, 50, 100)) console.log(it.next(10, 2, 1)) // 任务一:相乘 { "value": 2000, "done": false }任务二:相加 { "value": 340, "done": false }任务三:相减 { "value": 7, "done": false }
3、延迟执行
假设我们有一个数据表,我们想按大小顺序依次的获取数据,但是我们又不想提前给他排序,有可能我们根本就不去使用它,所以我们可以在第一次使用的时候再排序,做到延迟执行代码:
var table = { "d": 1, "b": 4, "c": 12, "a": 12 } table[Symbol.iterator] = function() { var _this = this; var keys = null; var index = 0; return { next: function() { if (keys === null) { keys = Object.keys(_this).sort(); } return { value: keys[index], done: index++>keys.length }; } } } for (var a of table) { console.log(a) } // a b c d
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がES6 イテレータと for.of ループ (詳細なチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。