ES 6-Iterator
15337 ワード
Iterator
紹介する
元の表示セットのデータ構造は、主に配列とオブジェクト、ES 6にMapとSetが追加されています.Iteratorは、異なるデータ構造を処理するための統一されたインターフェース機構です. Iteratorは、様々な異なるデータ構造のための統一アクセス機構 を提供するインターフェースである.任意のデータ構造は、Iteratorインターフェースを配置する限り、このようなデータ構造は巡回可能な であるという. ES 6は、デフォルトのIteratorインターフェースが、データ構造のSymbol.iterator属性に配置されている と規定している.は、様々なデータ構造のための統一的で簡便なアクセスインターフェース を提供する.は、データ構造のメンバがある順序で並べられるようにする. ES 6は、新しいエルゴード命令for...ofサイクルを作成しました.Iteratorインターフェースは、for...of消費量 を主に提供します.
プロセスを経るは、現在のデータ構造の開始位置を指すポインタオブジェクトを作成する.すなわち、エルゴードオブジェクトは、本質的には、ポインタオブジェクト である.ポインタオブジェクトのnextメソッドを初めて呼び出し、ポインタをデータ構造の最初のメンバ に向けることができる.ポインタオブジェクトのnextメソッドを第2回呼び出すと、ポインタはデータ構造の第2のメンバ を指す.ポインタオブジェクトnext方法を継続的に呼び出し、彼がデータ構造の終了位置 を指すまで. Aray Map セット TypedAray 関数のargmentsオブジェクト NodeListオブジェクト オブジェクト(Object)がデフォルトで展開されていない理由は、オブジェクトのどの属性が先に巡回されているか、どの属性が巡回されているかは不明で、開発者が手動で指定する必要があるからです.実際には、エルゴードは線形処理であり、任意の非線形データ構造に対してエルゴードインターフェースを配置することは、線形変換の展開に等しい.
オブジェクトがfor...of循環呼び出しのためのIteratorインターフェースを備えるには、Symbol.iteratorの属性にエルゴーバー生成方法を配置しなければならない.構造の割当値:配列とSet構造の値付けを行うと、デフォルトで が呼び出されます.拡張演算子:あるデータ構造がIteratorインターフェースを展開する限り、拡張演算子を用いて行列 に変換することができます. yield:yieldの後に付いているのはエルゴード構造で、インターフェースのエルゴードインターフェース を呼び出すことができます.他の場合:配列のエルゴードはエルゴードインターフェースを呼び出すので、任意の受け入れ配列がパラメータとして使用される場合、実はエルゴードインターフェースを呼び出しました. for…of Aray.from() Map(),Set(),WeakMap(),WeakSet() Promise.all() Promise.race() 文字列のIteratorインターフェース
Symbol.iterator方法の一番簡単な実現ですか?それともGenerator関数を使いますか?
エルゴードオブジェクトは、nextメソッドの他に、return方法とthrow方法があります.もしあなたが自分でエルゴードオブジェクトを書いて関数を生成するなら、nextメソッドは展開しなければならず、return方法とthrow方法は展開するかどうかを選択します.
returnメソッドの使用の場合は、for...ofループが早期に終了すると(通常はエラーやbreak文があります)、returnメソッドが呼び出されます.巡回が完了する前に、リソースを整理または解放する必要がある場合は、return方法を展開することができます.
for...ofサイクルは、循環配列およびクラス配列のデータ構造 を有してもよい. for...of循環内部で呼び出したのは、データ構造のSymbol.iterator方法 である.サイクルはキーを取得することを許可します. 配列のエルゴードインターフェースは、デジタルインデックスがある属性 だけを返します.
行列
配列元はiteratorインターフェースを備えています.すなわちSymbol.iterator属性がデフォルトで配備されています.for...ofサイクルは本質的にこのインターフェースを呼び出して生成されるエルゴードです.は同じfor...inのように簡潔な文法を持っていますが、for...inの欠点はありません. はforEach方法と違って、break、continue、returnと一緒に を使うことができます.は、エルゴードのすべてのデータ構造統一動作インターフェース を提供する.
for…inの欠点配列のキー名は数字ですが、for...inループは文字列をキーとして0'で、'1' です. for…inサイクルは、数字キーだけでなく、手動で追加された他のキーを巡回し、さらにプロトタイプチェーン上のキー を含む.場合によっては、for...inサイクルはキー名 を任意の順序で巡回します.
セットとMap構造
SetとMap構造も元々はIteratorインターフェースを持っています.そのままfor...ofサイクルを使うことができます.エルゴードの順序は、各メンバがデータ構造に追加される順序である . Setは時間を通して構成されています.戻りは1つの値です.一方、Mapは時間をかけて構成されています.戻りは1つの配列です.この配列の2つのメンバーはそれぞれ現在のMapメンバーのキー名とキー値 です.
いくつかのデータ構造は既存のデータ構造に基づいて計算されて生成される.例えば、ES 6の配列、Set、Mapは、サーキュラータオブジェクトに戻ります. entries()はエルゴードオブジェクトを返し、「キー名、キーパッド値」からなる配列を遍歴するために使用されます.キーパッドの名前はインデックス値です.セットに対して、キーの名前とキーの値は同じです.Map構造のIteratorインターフェースは、デフォルトではentriesメソッド を呼び出します. keys()は、すべてのキーを巡回するためにエルゴードオブジェクトを返します. values()は、全てのキー値 を巡回するためのエルゴードオブジェクトを返します.
これらの3つの方法は起動後に生成されたエルゴードオブジェクトで、エルゴードはすべて計算されて生成されたデータ構造です.
同様の配列のオブジェクトにはいくつかの種類があります.
普通のオブジェクトに対しては、for...of構造は直接使用できません.エラーが発生します.Iteratorインターフェースを配置してから使用しなければなりません.ただし、for...inサイクルは依然としてキーの名前を遍歴するために使用できます.
配列を例にとって、JavaScriptは様々な巡回文法を提供します.最初の書き方はforサイクルです.配列のキー名は数字ですが、for...inループは文字列をキーとして0'で、'1' です. for…inサイクルは、数字キーだけでなく、手動で追加された他のキーを巡回し、さらにプロトタイプチェーン上のキー を含む.場合によっては、for...inサイクルはキー名 を任意の順序で巡回します.
つまり、for…inサイクルは主にオブジェクトを遍歴するために設計されています.遍歴配列には適用されません.
for…ofサイクルは上記のいくつかのやり方に比べて、いくつかの著しい利点があります.は同じfor...inのように簡潔な文法を持っていますが、for...inの欠点はありません. はforEach方法と違って、break、continue、returnと一緒に を使うことができます.は、エルゴードのすべてのデータ構造統一動作インターフェース を提供する.
紹介する
元の表示セットのデータ構造は、主に配列とオブジェクト、ES 6にMapとSetが追加されています.Iteratorは、異なるデータ構造を処理するための統一されたインターフェース機構です.
// Symbol.iterator
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 }
作用プロセスを経る
// next
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
原生はIteratorインターフェースのデータ構造を備えている:オブジェクトがfor...of循環呼び出しのためのIteratorインターフェースを備えるには、Symbol.iteratorの属性にエルゴーバー生成方法を配置しなければならない.
// Iterator 。Symbol.iterator ,
class RangeIterator {
constructor(start, stop) {
this.value = start;
this.stop = stop;
}
[Symbol.iterator]() { return this; }
next() {
var value = this.value;
if (value < this.stop) {
this.value++;
return {done: false, value: value};
}
return {done: true, value: undefined};
}
}
function range(start, stop) {
return new RangeIterator(start, stop);
}
for (var value of range(0, 3)) {
console.log(value); // 0, 1, 2
}
//
// Symbol.iterator , iterator, next , ,
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
}
// Iterator
let obj = {
data: [ 'hello', 'world' ],
[Symbol.iterator]() {
const self = this;
let index = 0;
return {
next() {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false
};
} else {
return { value: undefined, done: true };
}
}
};
}
};
配列のようなオブジェクト(数値キーとlength属性が存在する)に対しては、Iteratorインターフェースを配置し、Symbol.iteratorメソッドが直接的に配列のIteratorインターフェースを参照するという簡便な方法があります.// NodeList , ,
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
//
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
[...document.querySelectorAll('div')] //
// Symbol.iterator
let iterable = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // 'a', 'b', 'c'
}
注:一般的なオブジェクト展開配列のSymbol.iteratorメソッドは、効果がありません.let iterable = {
a: 'a',
b: 'b',
c: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (let item of iterable) {
console.log(item); // undefined, undefined, undefined
}
Symbol.iteratorメソッドに対応するのがエルゴード生成関数ではない場合、エンジンはエラーとなります.var obj = {};
obj[Symbol.iterator] = () => 1;
[...obj] // TypeError: [] is not a function
Iteratorインターフェースを呼び出す場合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'];
// , , Iterator , 。 , Iterator , ,
//
var str = 'hello';
[...str] // ['h','e','l','l','o']
//
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
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 }
// , Iterator
var someString = "hi";
typeof someString[Symbol.iterator]
// "function"
var iterator = someString[Symbol.iterator]();
iterator.next() // { value: "h", done: false }
iterator.next() // { value: "i", done: false }
iterator.next() // { value: undefined, done:true }
// Symbol.iterator ,
var str = new String("hi");
[...str] // ["h", "i"]
str[Symbol.iterator] = function() {
return {
next: function() {
if (this._first) {
this._first = false;
return { value: "bye", done: false };
} else {
return { done: true };
}
},
_first: true
};
};
// str Symbol.iterator , (...) bye, hi
[...str] // ["bye"]
str // "hi"
IteratorインターフェースとGenerator関数Symbol.iterator方法の一番簡単な実現ですか?それともGenerator関数を使いますか?
// Symbol.iterator , yield
let myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
}
[...myIterable] // [1, 2, 3]
//
let obj = {
* [Symbol.iterator]() {
yield 'hello';
yield 'world';
}
};
for (let x of obj) {
console.log(x);
}
// "hello"
// "world"
エルゴードオブジェクトのreturn()、throw()エルゴードオブジェクトは、nextメソッドの他に、return方法とthrow方法があります.もしあなたが自分でエルゴードオブジェクトを書いて関数を生成するなら、nextメソッドは展開しなければならず、return方法とthrow方法は展開するかどうかを選択します.
returnメソッドの使用の場合は、for...ofループが早期に終了すると(通常はエラーやbreak文があります)、returnメソッドが呼び出されます.巡回が完了する前に、リソースを整理または解放する必要がある場合は、return方法を展開することができます.
// readLinesSync , , next , return
function readLinesSync(file) {
return {
[Symbol.iterator]() {
return {
next() {
return { done: false };
},
return() {
file.close();
return { done: true };
}
};
},
};
}
// , return
// , return ,
for (let line of readLinesSync(fileName)) {
console.log(line);
break;
}
// return ,
for (let line of readLinesSync(fileName)) {
console.log(line);
throw new Error();
}
注:return方法は一つのオブジェクトに返さなければなりません.これはGenerator規格によって決められたthrow方法です.主にGenerator関数に合わせて使用されます.一般的なエルゴードオブジェクトはこの方法が使えません.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
}
行列
配列元はiteratorインターフェースを備えています.すなわちSymbol.iterator属性がデフォルトで配備されています.for...ofサイクルは本質的にこのインターフェースを呼び出して生成されるエルゴードです.
// obj arr Symbol.iterator , obj for...of , arr
const arr = ['red', 'green', 'blue'];
for(let v of arr) {
console.log(v); // red green blue
}
const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);
for(let v of obj) {
console.log(v); // red green blue
}
for...ofサイクルは、配列例のforEach方法に代わることができます.const arr = ['red', 'green', 'blue'];
arr.forEach(function (element, index) {
console.log(element); // red green blue
console.log(index); // 0 1 2
});
JavaScriptの元のfor…inサイクルは、対象のキー名しか獲得できません.直接キーの値を取得することはできません.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
}
注:for...ofループは、エルゴードインターフェースを呼び出します.配列のエルゴードインターフェースは、数値索引の属性だけを返します.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"
}
for...ofの利点:for…inの欠点
セットとMap構造
SetとMap構造も元々はIteratorインターフェースを持っています.そのままfor...ofサイクルを使うことができます.
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
注:let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
console.log(pair);
}
// ['a', 1]
// ['b', 2]
for (let [key, value] of map) {
console.log(key + ' : ' + value);
}
// a : 1
// b : 2
生成したデータ構造を計算します.いくつかのデータ構造は既存のデータ構造に基づいて計算されて生成される.例えば、ES 6の配列、Set、Mapは、サーキュラータオブジェクトに戻ります.
これらの3つの方法は起動後に生成されたエルゴードオブジェクトで、エルゴードはすべて計算されて生成されたデータ構造です.
let arr = ['a', 'b', 'c'];
for (let pair of arr.entries()) {
console.log(pair);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
類似配列のオブジェクト同様の配列のオブジェクトにはいくつかの種類があります.
//
let str = "hello";
for (let s of str) {
console.log(s); // h e l l o
}
// 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', 'b');
// 'a'
// 'b'
文字列では、for...ofループは32ビットのUTF-16文字を正しく認識するという特徴があります.for (let x of 'a\uD83D\uDC0A') {
console.log(x);
}
// 'a'
// '\uD83D\uDC0A'
すべての類似配列のオブジェクトがIteratorインターフェースを持っているわけではなく、簡単な解決方法として、Aray.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);
}
オブジェクト普通のオブジェクトに対しては、for...of構造は直接使用できません.エラーが発生します.Iteratorインターフェースを配置してから使用しなければなりません.ただし、for...inサイクルは依然としてキーの名前を遍歴するために使用できます.
let es6 = {
edition: 6,
committee: "TC39",
standard: "ECMA-262"
};
for (let e in es6) {
console.log(e);
}
// edition
// committee
// standard
for (let e of es6) {
console.log(e);
}
// TypeError: es6[Symbol.iterator] is not a function
一つの解決方法は、オブジェクトのキー名を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
他のエルゴード文法との比較配列を例にとって、JavaScriptは様々な巡回文法を提供します.最初の書き方はforサイクルです.
//
for (var index = 0; index < myArray.length; index++) {
console.log(myArray[index]);
}
したがって、配列は内蔵のforEach方法を提供します.// , forEach ,break return
myArray.forEach(function (value) {
console.log(value);
});
for...inサイクルは配列のキー名を遍歴することができます.for (var index in myArray) {
console.log(myArray[index]);
}
for...inサイクルのいくつかの欠点:つまり、for…inサイクルは主にオブジェクトを遍歴するために設計されています.遍歴配列には適用されません.
for…ofサイクルは上記のいくつかのやり方に比べて、いくつかの著しい利点があります.
for (let value of myArray) {
console.log(value);
}
// break , for...of
// 1000 。 1000, break for...of
for (var n of fibonacci) {
if (n > 1000)
break;
console.log(n);
}