Es6-iterator
ES6-イテレーター
イテレーターの紹介
イテレータは、オブジェクトのコレクションに一度に1つずつアクセスできるようにするオブジェクトです。
次の組み込み型はデフォルトで反復可能です-
- ひも
- アレイ
- Map
- Set
キーが [Symbol.iterator] である関数を実装し、イテレーターを返す場合、オブジェクトは*反復可能*と見なされます。 for … ofループを使用して、コレクションを反復できます。
例
次の例では、 for..of ループを使用して、配列を宣言し、マークを付けて繰り返し処理します。
<script>
let marks = [10,20,30]
//check iterable using for..of
for(let m of marks){
console.log(m);
}
</script>
上記のコードの出力は以下のようになります-
10
20
30
例
次の例では、配列を宣言し、イテレータオブジェクトをマークして取得します。 * [Symbol.iterator]()を使用して、イテレーターオブジェクトを取得できます。 イテレータのnext()メソッドは、 *'value' および 'done' プロパティを持つオブジェクトを返します。 'done’はブール値であり、コレクション内のすべてのアイテムを読み取った後にtrueを返します。
<script>
let marks = [10,20,30]
let iter = marks[Symbol.iterator]();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
</script>
上記のコードの出力は以下のようになります-
{value: 10, done: false}
{value: 20, done: false}
{value: 30, done: false}
{value: undefined, done: true}
カスタム反復可能
JavaScriptの特定のタイプは反復可能です(例: 配列、マップなど)が他の場合はありません(例: クラス)。 デフォルトで反復可能でないJavaScriptタイプは、反復可能プロトコルを使用して反復できます。
次の例では、複数の顧客オブジェクトを配列として格納する CustomerList という名前のクラスを定義しています。 各顧客オブジェクトには、firstNameプロパティとlastNameプロパティがあります。
このクラスを反復可能にするには、クラスが* [Symbol.iterator]()関数を実装する必要があります。 この関数は、反復子オブジェクトを返します。 イテレータオブジェクトには、オブジェクト *\ {value: 'customer'、done:true/false} を返す関数 next があります。
<script>
//user defined iterable
class CustomerList {
constructor(customers){
//adding customer objects to an array
this.customers = [].concat(customers)
}
//implement iterator function
[Symbol.iterator](){
let count=0;
let customers = this.customers
return {
next:function(){
//retrieving a customer object from the array
let customerVal = customers[count];
count+=1;
if(count<=customers.length){
return {
value:customerVal,
done:false
}
}
//return true if all customer objects are iterated
return {done:true}
}
}
}
}
//create customer objects
let c1={
firstName:'Sachin',
lastName:'Tendulkar'
}
let c2={
firstName:'Rahul',
lastName:'Dravid'
}
//define a customer array and initialize it let customers=[c1,c2]
//pass customers to the class' constructor
let customersObj = new CustomerList(customers);
//iterating using for..of
for(let c of customersObj){
console.log(c)
}
//iterating using the next() method
let iter = customersObj[Symbol.iterator]();
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
</script>
上記のコードの出力は次のようになります-
{firstName: "Sachin", lastName: "Tendulkar"}
{firstName: "Rahul", lastName: "Dravid"}
{
done: false
value: {
firstName: "Sachin",
lastName: "Tendulkar"
}
}
{
done: false
value: {
firstName: "Rahul",
lastName: "Dravid"
}
}
{done: true}
ジェネレータ
ES6より前は、JavaScriptの関数は実行完了モデルに従っていました。 ES6には、途中で停止し、停止したところから続行できるジェネレーターと呼ばれる機能が導入されています。
ジェネレーターは、関数名の前にアスタリスク*文字を付け、1つ以上の yield ステートメントを含みます。 yield キーワードはイテレーターオブジェクトを返します。
構文
function * generator_name() {
yield value1
...
yield valueN
}
例
この例では、3つのyieldステートメントでジェネレーター関数 getMarks を定義しています。 通常の関数とは異なり、* generator関数getMarks()*は、呼び出されても関数を実行しませんが、ジェネレーター関数内のコードの実行に役立つイテレーターオブジェクトを返します。
- markIter.next()の最初の呼び出しで、最初の操作が実行され、yieldステートメントがジェネレーターの実行を一時停止します。 * markIter.next()*への後続の呼び出しは、次の *yield 式までジェネレーター関数を再開します。
<script>
//define generator function
function * getMarks(){
console.log("Step 1")
yield 10
console.log("Step 2")
yield 20
console.log("Step 3")
yield 30
console.log("End of function")
}
//return an iterator object
let markIter = getMarks()
//invoke statements until first yield
console.log(markIter.next())
//resume execution after the last yield until second yield expression
console.log(markIter.next())
//resume execution after last yield until third yield expression
console.log(markIter.next())
console.log(markIter.next())//iteration is completed;no value is returned
</script>
上記のコードの出力は以下のようになります-
Step 1
{value: 10, done: false}
Step 2
{value: 20, done: false}
Step 3
{value: 30, done: false}
End of function
{value: undefined, done: true}
例
次の例では、
- evenNumberGeneratorジェネレーター関数。
以下に示すように、* next()または *for of ループを使用して、すべての偶数を反復処理できます。
<script>
function * evenNumberGenerator(){
let num = 0;
while(true){
num+=2
yield num
}
}
//display first two elements
let iter = evenNumberGenerator();
console.log(iter.next())
console.log(iter.next())
//using for of to iterate till 12
for(let n of evenNumberGenerator()){
if(n==12)break;
console.log(n);
}
</script>
上記のコードの出力は次のようになります-
{value: 2, done: false}
{value: 4, done: false}
2
4
6
8
10