この記事では主にES6のイテレータ(Iterator)とfor.ofループの使い方の学習まとめを紹介していますが、編集者がとても良いと思ったので、参考としてシェアさせていただきます。編集者をフォローして見てみましょう。皆さんのお役に立てれば幸いです。
1. イテレーターとは何ですか?
ジェネレーターの概念は Java、Python、その他の言語で利用でき、ES6 は JavaScript にも追加されました。 Iterator を使用すると、コレクション変数とインデックス変数を初期化する必要がなくなり、代わりに反復子オブジェクトの next メソッドを使用してコレクション内の次の項目の値を返します。これはプログラミングに特化しています。
イテレータは特別なインターフェイスを持つオブジェクトです。 next() メソッドが含まれており、この呼び出しは 2 つの属性、つまり value と Done を含むオブジェクトを返します。Value は現在の位置の値を表し、done は反復が完了したかどうかを表します。これが true の場合、next の呼び出しは無効になります。
ES5 のコレクションの走査は通常 for ループであり、配列にも forEach メソッドがあり、ES6 では Map と Set が追加され、イテレーターはすべてのコレクション データを統一的に処理できます。イテレータはインターフェイスです。データ構造がイテレータ インターフェイスを公開している限り、反復を完了できます。 ES6 では新しいトラバーサル コマンド for...of ループが作成され、Iterator インターフェイスは主に for...of による消費に使用されます。
2. イテレータの使い方
1. デフォルトの Iterator インターフェイス
Iterator インターフェイスがデータ構造にデプロイされている限り、このデータ構造は「反復可能」になります。 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']
( 3) Generator 関数の yield* 式 (次の章で紹介します)
// 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
まず欠点を見てみましょう。 forEach メソッドの配列:
// code5 myArray.forEach(function (value) { console.log(value); });
オブジェクト 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); } }
(1) Array
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
(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'
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
四、结语
本章内容,重点是明白 Iterator 接口的机制,以及 for...of 循环的使用方法。
相关推荐:
关于PHP聚合式迭代器接口IteratorAggregate用法分享
以上がES6イテレータとfor.ofループの使い方の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。