はじめに
スプレッド構文...
やfor/of
によって配列要素を1つずつ取得して変数に代入したり、処理したりすることができます。
for/of
などによる繰り返し処理はどのようなオブジェクトに対しても行えるわけではなく、反復可能オブジェクトと呼ばれるオブジェクトに限られます。
反復可能オブジェクトとは、Symbol.iterator
メソッドを持つオブジェクトのことで、Symbol.iterator
メソッドはイテレータを返します。
この記事では反復処理を可能とする、イテレータの概要についてまとめてみたいと思います。
反復可能オブジェクト
反復可能オブジェクトは、Symbol.iterator
メソッドを持つオブジェクトのことです。
Symbol.iterator
メソッドはイテレータを返します。
組み込みの反復可能オブジェクトには、String
やArray
、Map
やSet
などがあります。
自作の反復可能オブジェクトを作成することも可能で、Symbol.iterator
メソッドやイテレータを自前で実装します。
Synbol.iterator
メソッドを定義して、「0から9までのランダムな数値」から9までを反復する、反復可能オブジェクトは次のように作ることができます。
const iterableObject = {
[Symbol.iterator]() {
const random = Math.floor(Math.random() * 10) // 0から9の整数値をランダムに生成
let restNum = random
return {
next() {
restNum++
if (restNum < 10) {
return { done: false, value: restNum }
} else {
return { done: true, value: undefined }
}
}
}
}
}
for(const num of iterableObject){
console.log(num)
}
オブジェクトの中に[Symbol.iterator](){...}
の形でメソッドを定義しています。
このメソッドが返しているオブジェクトがイテレータです。
イテレータ
イテレータとは、要素に順にアクセスするための仕組みのことで、JavaScript ではnext()
メソッドを実装したオブジェクトのことをイテレータと呼びます。
next()
メソッド
next()
メソッドは、反復結果オブジェクト(IteratorResult)を返すメソッドです。
反復結果オブジェクトとは、done
、value
プロパティを持つオブジェクトで、done
にはboolean
が、value
には任意の値1がはいります。
next()
の仕様
ECMAScript 仕様書には、next()
について次のように記載されています。
value
a function that returns an IteratorResult object
next()
メソッドの返り値は反復結果オブジェクトであることが明記されていますね。
また、next()
は以下の要件を満たす必要があることが記されています。
Requirement
The returned object must conform to the IteratorResult interface. If a previous call to the next method of an Iterator has returned an IteratorResult object whose "done" property is true, then all subsequent calls to the next method of that object should also return an IteratorResult object whose "done" property is true. However, this requirement is not enforced.
(拙訳)
next
メソッドから返されるオブジェクトは IteratorResult
インターフェースに準拠すること。
イテレータが呼び出したnext
メソッドが、done
がtrue
の反復結果オブジェクトを返した場合、それ以降のnext()
メソッドの呼び出しもすべて、done
がtrue
の反復結果オブジェクトを返す必要がある。しかし、この要件は強制されない。
next()
メソッドは反復結果オブジェクトを返すことが最低限の要件となっているわけですね。
done
プロパティ
done
については、仕様では以下のような要件となっています。
Requirement
This is the result status of an iterator next method call. If the end of the iterator was reached "done" is true. If the end was not reached "done" is false and a value is available. If a "done" property (either own or inherited) does not exist, it is considered to have the value false.
done
はイテレータのnext()
メソッドの結果を表すプロパティです。
イテレータが終端に達した時にtrue
となります。
イテレータが終端に達していない時はfalse
となり、値が利用可能です。
done
プロパティ(自身のプロパティまたは継承したプロパティ)がないときには、false
として扱われます。
value
プロパティ
value
については、仕様では以下のような要件となっています。
Requirement
If done is false, this is the current iteration element value. If done is true, this is the return value of the iterator, if it supplied one. If the iterator does not have a return value, "value" is undefined. In that case, the "value" property may be absent from the conforming object if it does not inherit an explicit "value" property.
value
は、done
がfalse
のときには現在の反復要素の値をもちます。
done
がtrue
のときにはイテレータに設定されている返り値となります。
イテレータが返り値をもたないときは、value
がundefined
となるか、明示的なvalue
プロパティを継承していないならばvalue
プロパティ自体が省略されることがあります。
ここで、先ほどの例でSynbol.iterator
が返していたオブジェクトをみてみます。
{
next() {
restNum++
if (restNum < 10) {
return { done: false, value: restNum }
} else {
return { done: true, value: undefined }
}
}
}
next()
は{ done: false, value: restNum }
か{ done: true, value: undefined }
という反復結果オブジェクトを返しており、done
がfalse
のときにのみ値が設定されていることがわかります。
また、一度done
がtrue
となると、それ以降は処理が反復されたとしてもrestNum < 10
を満たすことはなく、常にdone
がtrue
を返すこともわかります。
確かにこのオブジェクトはイテレータの仕様要件を満たしていますね。
まとめ
複数の似た名前のオブジェクトが出てきたため、最後にまとめてみます。
-
反復可能オブジェクト(Iterable Object)
-
Symbol.iterator
メソッドを持つオブジェクト -
Array
やMap
は組み込みの反復可能オブジェクト
-
-
イテレータ(Iterator)
-
next()
メソッドを持つオブジェクト -
Symbol.iterator
メソッドはイテレータを返す
-
-
反復結果オブジェクト(Iterator Reslut Object)
- イテレータの
next()
メソッドから返されるオブジェクト -
done
とvalue
プロパティをもつ
- イテレータの
-
任意の値とは、仕様ではECMAScript Language Typesと呼ばれる値です。 ↩