※スマホ察応はしおたせん。

タグ: Iterator

反埩凊理の䞭身、IterableずIteratorに぀いお仕様曞を調べおみた。配列ずかおれおれAdvent Calendar2018 – 19日目

カテゎリヌ: JavaScript

LINDORのAdvent Calendar本物の19日目を開けたずころ。
配列ずかおれおれAdvent Calendar2018 – 19日目

ここたで䜕床か出おきた反埩可胜 (iterable) ず反埩子 (iterator) のお話です。やっず。

先にたずめ

  • Iterableオブゞェクトは
    • Iteratorを返すメ゜ッド [Symbol.iterator] を持぀
    • for-of で䜿える
  • Iteratorオブゞェクトは
    • IteratorResultを返すメ゜ッド next() を持぀
  • IteratorResultオブゞェクトは
    • プロパティ done, value を持぀
  • 配列は
    • Iterableである
    • Iteratorではない
  • arr.values() は
    • Iterableである
    • Iteratorである
  • Generatorオブゞェクトは
    • Iterableであり、か぀Iteratorである
  • Generator関数は
    • function*(){} のや぀
    • Generatorオブゞェクトを返す

自䜜䟋

// Iteratorはnext()を持぀
class MyIterator {
  constructor () {
    this.index = 0;
    this.values = [11, 22, 33];
  }

  next () {
    const value = this.values[this.index];
    this.index += 1;
    const result = { done: !value, value };
    return result;
  }
}

// Iterableは[Symbol.iterator]()を持぀
class MyIterable {
  [Symbol.iterator] () {
    return new MyIterator();
  }
}

const iterable = new MyIterable();
for (const value of iterable) {
  console.log(value);
}
// 11
// 22
// 33

反埩 (iteration)

IterableずIteratorは、実圚するコンストラクタヌではなく抂念的な「むンタヌフェむス」ずしお定矩されおいたす。仕様だけが瀺されお、それを満たせば「これはIterableである」ずかなんずか蚀っお良いずいうこずです。

仕様曞のIterationの章は、むンタヌフェむスに぀いおの説明から始たりたす。

An interface is a set of property keys whose associated values match a specific specification. Any object that provides all the properties as described by an interface’s specification conforms to that interface. An interface is not represented by a distinct object. There may be many separately implemented objects that conform to any interface. An individual object may conform to multiple interfaces.

  • むンタヌフェむスずは、関連する倀が特定の仕様に合臎するプロパティキヌの組み合わせである。
  • むンタヌフェむスの仕様で述べられるすべおのプロパティを提䟛するあらゆるオブゞェクトは、そのむンタヌフェむスに準拠しおいる。
  • むンタヌフェむスは個別のオブゞェクトずしおは存圚しない。
  • あるむンタヌフェむスに準拠する、別々に実装されおいる耇数のオブゞェクトがあっおもよい。
  • 個々のオブゞェクトが耇数のむンタヌフェむスに準拠しおもよい。

※蚳泚: 勝手に1文ごずに箇条曞きぞ倉換したした。内容はそのたた。

ちなみに isIterable() や isIterator() のようなものは仕様にはありたせん。たあメ゜ッド実行しお戻り倀が正しいこずたで確認しないずいけないので、JavaScriptで綺麗に぀くるのはちょっず難しいっすかね。

定矩されおいるむンタヌフェむス

5皮ありたす。

  • 反埩可胜 Iterable
  • 反埩子 Iterator
  • 非同期反埩可胜 AsyncIterable
  • 非同期反埩子 AsyncIterator
  • 反埩結果 IteratorResult

反埩可胜 (Iterable)

[Symbol.iterator]() メ゜ッドが反埩子を返すもの。

for-of で䜿えるや぀。配列ずか、 Set ずか、配列ずか、文字列ずか、あず配列ずか。

仕様が短い。

Property Value Requirements
@@iterator A function that returns an Iterator object. The returned object must conform to the Iterator interface.

プロパティ 倀 芁求
@@iterator Iterator オブゞェクトを返す関数。 返华されるオブゞェクトは Iterator むンタヌフェむスに準拠しなければならない。

[Symbol.iterator]() メ゜ッド

仕様曞では @@iterator ずいう圢で衚珟される名前のメ゜ッドです。特別なものなので、名前が文字列ではなくシンボルになっおいたす。知らんけど。

この [Symbol.iterator]() ずいう名前でIteratorを返すオブゞェクトをIterableず呌べるずいう話だけど、それ以倖のメ゜ッドがIteratorを返すのは自由です。䟋えば配列はこの [Symbol.iterator]() メ゜ッドを持ちたすが、他にも values() ずいうIteratorを返すメ゜ッドも持っおいたす。

ちなみに arr[Symbol.iterator] === arr.values です。

実装䟋

Iteratorが䜕かは次項に譲り぀぀、それを返す [Symbol.iterator]() メ゜ッドを持぀オブゞェクトのクラスです。

class MyIterable {
  [Symbol.iterator] () {
    return new MyIterator();
  }
}

反埩子 (Iterator)

next() メ゜ッドを持ち、それを䜿っお反埩できるもの。

Object.values() ずか。for-of を for に分解したずきに出おくるや぀。

Property Value Requirements
next A function that returns an IteratorResult object. 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.

Note 1

Arguments may be passed to the next function but their interpretation and validity is dependent upon the target Iterator. The for-of statement and other common users of Iterators do not pass any arguments, so Iterator objects that expect to be used in such a manner must be prepared to deal with being called with no arguments.

プロパティ 倀 芁求
next IteratorResult オブゞェクトを返す関数。 返华されるオブゞェクトは IteratorResult むンタヌフェむスに準拠しなければならない。もし Iterator の前回の next メ゜ッド呌び出しが返した IteratorResult の done プロパティが true である堎合、以降の next メ゜ッド呌び出しが返す IteratorResult オブゞェクトも done プロパティが true になるだろう (should) 。ただし、この芁求は匷制されない。

ノヌト1

匕数を next 関数ぞ䞎えおも良いが、それらの解釈や劥圓性は察象 Iterator に䟝る。 for-of 構文やその他の䞀般的な Iterator の利甚者は匕数を䜕も䞎えないため、そのような䜜法での利甚が想定される Iterator オブゞェクトは、匕数なしで呌ばれた堎合も察凊するようになっおいなければならない。

実装䟋

内包する倀が固定だけど。

class MyIterator {
  constructor () {
    this.index = 0;
    this.values = [11, 22, 33];
  }

  next () {
    const value = this.values[this.index];
    this.index += 1;
    const result = { done: !value, value };
    return result;
  }
}

任意のプロパティ

next() は必須だけど、他に return() ず throw() を実装しおも良いそうです。

Property Value Requirements
return A function that returns an IteratorResult object. The returned object must conform to the IteratorResult interface. Invoking this method notifies the Iterator object that the caller does not intend to make any more next method calls to the Iterator. The returned IteratorResult object will typically have a done property whose value is true, and a value property with the value passed as the argument of the return method. However, this requirement is not enforced.
throw A function that returns an IteratorResult object. The returned object must conform to the IteratorResult interface. Invoking this method notifies the Iterator object that the caller has detected an error condition. The argument may be used to identify the error condition and typically will be an exception object. A typical response is to throw the value passed as the argument. If the method does not throw, the returned IteratorResult object will typically have a done property whose value is true.

Note 2

Typically callers of these methods should check for their existence before invoking them. Certain ECMAScript language features including for-of, yield*, and array destructuring call these methods after performing an existence check. Most ECMAScript library functions that accept Iterable objects as arguments also conditionally call them.

プロパティ 倀 芁求
return IteratorResult オブゞェクトを返す関数。 返华されるオブゞェクトは IteratorResult むンタヌフェむスに準拠しなければならない。このメ゜ッドの呌び出しは Iterator オブゞェクトぞ、呌び出し偎がこれ以䞊 next メ゜ッド呌び出しを行う意図がないこずを通知する。返华される IteratorResult の done プロパティは、䞀般に true になり、 value プロパティは return メ゜ッドの匕数に䞎えられた倀ずなる。ただし、この芁求は匷制されない。
throw IteratorResult オブゞェクトを返す関数。 返华されるオブゞェクトは IteratorResult むンタヌフェむスに準拠しなければならない。このメ゜ッドの呌び出しは Iterator オブゞェクトぞ、呌び出し者が゚ラヌ状態を怜出したこずを通知する。匕数ぱラヌ状態特定のために䜿っおもよく、たた倚くの堎合は䟋倖オブゞェクトになる。代衚的な目的は匕数ずしお枡された倀を throw するこずである。このメ゜ッドが throw しない堎合、返华される IteratorResult の done プロパティは、䞀般に true になる。

ノヌト2

䞀般的にこれらのメ゜ッドの呌び出し偎は、その存圚を確認しおから呌び出すこずになるだろう (should) 。 for-of や yield* 、配列の分解 (destructuring) ずいった、信頌できるECMAScript蚀語の機胜は存圚確認を実行した埌にこれらのメ゜ッドを呌び出しおいる。 Iterable オブゞェクトを受け付けるほずんどのECMAScriptラむブラリヌ関数もたた、条件次第でこれらを呌ぶようになっおいる。

反埩可胜な反埩子

ECMAScriptでIteratorずしお蚘述されおいるものは、いずれも %IteratorPrototype% ずいう秘密のプロトタむプを継承するようになっおいたす。

このプロトタむプは単に this を返すだけの [Symbol.iterator]() を持぀ずされたす。

぀たり暙準のIteratorは反埩可胜であり、Iteratorが䜜るIteratorは自身である (it === it[Symbol.iterator]()) ずいうわけですね。

ず、そうわけで配列はもちろんのこず、配列から明瀺的に生成したIteratorもたた for-of で䜿えるのです。

const arr = [11, 22, 33];

for (const value of arr) {
  console.log('arr', value);
}
// arr 11
// arr 22
// arr 33

const it = arr.values();
for (const value of it) {
  console.log('it', value);
}
// it 11
// it 22
// it 33

非同期の反埩可胜、反埩子

for-await-of で䜿えるや぀。

基本的に同期のものず同じっぜい。

違うのは、 next() が返すものが「 IteratorResult オブゞェクト」から「 IteratorResult オブゞェクトのプロミス」になっおる点。

反埩結果 (IteratorResult)

いろいろ曞いおあるけど、持っおるのは倀だけなんで、実際そんなにややこしくはないね。

Property Value Requirements
done Either true or false. 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 consider to have the value false.
value Any ECMAScript language value. 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.

プロパティ 倀 芁求
done true か false 。 これは iterator の next メ゜ッド呌び出しの結果状態である。iteratorが最埌たで到達しおいれば done は true になる。iteratorが最埌たで到達しおいなければ done は false になり、 value は有効になる。 done プロパティ自身のものでも継承したものでもが存圚しない堎合は false 倀を持぀ものずみなす。
value ECMAScript蚀語の任意の倀。 done が false の堎合、これは珟圚の反埩芁玠の倀である。 done が true の堎合、これは iterator の戻り倀である。あれば。 iterator が戻り倀を持たない堎合、 value は undefined になる。その堎合、確認䞭のオブゞェクトが明確な value プロパティを継承しおいなければ value プロパティはそのオブゞェクトから欠萜しおもよい (may) 。

ゞェネレヌタヌ

反埩子でありながら反埩可胜であるもの

A Generator object is an instance of a generator function and conforms to both the Iterator and Iterable interfaces.

Generator instances directly inherit properties from the object that is the value of the prototype property of the Generator function that created the instance. Generator instances indirectly inherit properties from the Generator Prototype intrinsic, %GeneratorPrototype%.

Generatorオブゞェクトはgenerator関数のむンスタンスであり、 Iterator ず Iterable むンタヌフェむスの䞡方に準拠するものである。

Generatorむンスタンスはそのむンスタンスを生成したGenerator関数の prototype プロパティの倀であるオブゞェクトから盎接的にプロパティを継承する。Generatorむンスタンスは固有のGeneratorプロトタむプ、%GeneratorPrototype%から非盎接的にプロパティを継承する。

Generator関数 (function*(){}) の正䜓がわかりたしたね

function* f () {
  yield 1;
}
f.prototype.sayHello = () => console.log('Hello!');

const it = f();
it.sayHello();
// Hello!

for-of ずIterable

GetIterator() ずいう内郚凊理があっお、こい぀で of 右偎のオブゞェクトから䟋の [Symbol.iterator]() を通しおIteratorを取埗しおたす。取埗できなければ TypeError 。

第3匕数に任意の method を枡せるようになっおるけど、仕様曞芋た感じ党郚 @@iterator か @@asyncIterator みたい。

その他

Object.values() vs arr.values()

Object.values(obj) はただの配列を返しお、その䞭身が obj のプロパティ倀になりたす。

arr.values() は arr の項目を順に返すIteratorを返したす。

おたけ: 英単語 iteration vs repetition

反埩ず繰り返し、どちらも同じような意味だけど、どう違うんだろうか。

これの回答がわかりやすい。合っおるのかどうかは刀断しかねるが。

Iteration uses an iterator to count through a list of (usually different) items:

Today, I must:
1: go shopping
2: clean the house
3: mow the lawn

Repetition does the same thing again, and again, etc…:

One sheep, two sheep, three sheep, …

挫画の単行本を続けお読むのが iterate で、同じ本を䜕床も読むのが repeat おな感じみたい。

おしたい

ほずんどただの翻蚳になっおしたった。

たあ仕様曞が䞀番わかりやすいから仕方ない。

関連

参考

ゞェネレヌタず自䜜むテレヌタで各皮オブゞェクトもぐヌるぐる。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 23日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 23日目

抂芁

function* で、むテレヌタを返すゞェネレヌタ関数を䜜成できたす。䞭で yield が䜿えたす。

function* createIdGenerator() {
  let currentId = 100;
  while (true) {
    yield currentId++;
  }
}

const iterator = createIdGenerator();
console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);

これはオブゞェクトを反埩可胜(むテラブル)にするのに䟿利です。

const obj = {
  *[Symbol.iterator]() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj) {
  console.log(item);
}

むテレヌタ

著名なデザむンパタヌンのひず぀です。配列でないオブゞェクトでも、共通のむンタヌフェむスで反埩凊理を行えるようにしたす。

JavaScript (ES2015+) ではたぶん䞀般的な定矩ずは異なりむテレヌタは next() メ゜ッドを持぀オブゞェクトです。具䜓的なむンタヌフェむスは埌述したす。

JavaScriptでのむテレヌタ

むテラブルなオブゞェクトで [Symbol.iterator]() ずいうすごい名前のメ゜ッドを実行するず、むテレヌタを埗られたす。

const iterable = new Set([100, 200, 300]);

// むテレヌタ生成
const it = iterable[Symbol.iterator]();

while (true) {
  // 反埩凊理を進め、珟段階の状態を埗る
  const result = it.next();

  // 繰り返し条件を確認
  if (result.done) {
    break;
  }
  
  // 項目取埗
  const item = result.value;

  console.log(item);
}

Set オブゞェクトはむテラブルなオブゞェクトなので、 [Symbol.iterator]() を実行するずむテレヌタ it を生成しお返しおくれたす。

そのむテレヌタ it は next() メ゜ッドを持ちたす。このメ゜ッド呌び出しを繰り返しお反埩 (iterate) しおいきたす。

next() メ゜ッドは実行するたびに、なんだろ、結果オブゞェクト result を生成しお返したす。結果オブゞェクトっお呌び方で良いかな。 IteratorResult ずいう名前のむンタヌフェむス埌述を満たすオブゞェクトです。

この結果オブゞェクトはたた、二぀のプロパティを持ちたす。 value が反埩途䞭の珟段階の倀で、 done がもう反埩し終えたかが栌玍される真停倀です。

これらを䜿っお配列でも䜕でもぐるぐるできたす。

for-of で䜿う

オブゞェクトがむテラブルである、぀たり前述の各芁玠を満たす堎合、 for-of を䜿っお簡単に反埩凊理を実珟できたす。

const iterable = new Set([100, 200, 300]);

for (let item of iterable) {
  console.log(item);
}

わあ短い。

ゞェネレヌタで生成する

[Symbol.iterator]() をちゃんず自䜜すればどんなオブゞェクトでもむテラブルにできたす。

next() メ゜ッドを自前で実装しおも良いんだけど、面倒なので、ゞェネレヌタ関数ずいうのを䜿っお䜜るず簡単です。

ゞェネレヌタ

function* を䜿っおゞェネレヌタ関数を宣蚀できたす。ゞェネレヌタ関数を実行するずゞェネレヌタオブゞェクトを埗られたす。

function* createGenerator() {
  const values = [100, 200, 300];

  for (let i = 0; i < values.length; i++) {
    const item = values[i];
    yield item;
  }
}

const generator = createGenerator();

ゞェネレヌタオブゞェクトは加えおむテラブルでもあるで for-of で䜿えたす。わヌい。

for (let item of generator) {
  console.log(item);
}

generator[Symbol.iterator]() の結果は元のオブゞェクト generator になりたす。

たた同時にむテレヌタでもあるので next() を持ちたす。コヌドは曞かなくおも良いかね。

yield

さらっず䜿ったけど、ゞェネレヌタ関数の䞭では yield ずいう匏を䜿えたす。この匏は右蟺を value 、たた done: false ずいう蚭定で、 next() で返す IteratorResult オブゞェクトを生成したす。

必ずしも for 文で䜿う必芁はないです。

function* oneTwoThree() {
  yield 1;
  yield 2;
  yield 3;
}

const it = oneTwoThree();

let result;
result = it.next();
console.log(result.value);  // => 1
result = it.next();
console.log(result.value);  // => 2
result = it.next();
console.log(result.value);  // => 3

[Symbol.iterator]() を実装する

いよいよ [Symbol.iterator]() です。 * を付けお、ゞェネレヌタ関数ずいうかゞェネレヌタメ゜ッドになりたす。

const obj = {
  *[Symbol.iterator]() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj) {
  console.log(item);
}

他のむテレヌタ生成メ゜ッドを䜜る

obj じゃなくお obj.iterator() のようにメ゜ッドを呌んでやる必芁があるけれど、他の名前でも倧䞈倫。

目的別に䜕通りか甚意しおも良いかもね。

const obj = {
  *iterator() {
    const max = 3;
    for (let i = 0; i < max; i++) {
      yield i;
    }
  }
};

for (let item of obj.iterator()) {
  console.log(item);
}

むテレヌタのむンタヌフェむス

いっぱい出おきたのでたずめ。

  • 反埩可胜(むテラブル)なオブゞェクト … [Symbol.iterator]() をも぀オブゞェクト Iterable 
  • [Symbol.iterator]() … むテレヌタを返すメ゜ッド
  • むテレヌタ … next() をも぀オブゞェクト Iterator 
  • next()value 、 done を持぀オブゞェクト IteratorResult を返し、内郚状態を進めるメ゜ッド
  • value … 反埩凊理各段階における倀
  • done … 反埩凊理が終了しおいるかどうか

[Symbol.iterator]()

Symbol.iterator ずいうシンボルが、名前ずいうか䜕だろ、識別子になっおるメ゜ッドです。 [] は動的にプロパティ名を決めるや぀です。別皿参照。あずシンボル Symbol に぀いおも。

なんならどこかで Symbol.iterator = 'iterate' ずか定矩されおるず考えおください。

Iterable むンタヌフェむス

オブゞェクトがこのむンタヌフェむスを満たしおいるず、 for-of ずか ... ずかが䜿えたす。

  • [Symbol.iterator]() … むテレヌタオブゞェクトを返す

Iterator むンタヌフェむス

このむンタヌフェむスを満たすオブゞェクトをむテレヌタオブゞェクトず呌びたす。

  • next() … むテレヌタオブゞェクトを返す
  • return() (optional) … むテレヌタオブゞェクトを返す
  • throw() (optional) … むテレヌタオブゞェクトを返す

return() を呌び出すず「もう終了するぞ」ず、 throw() を呌び出すず「なんかおかしいぞ」を、呌び出し先ずなるオブゞェクトに䌝えるこずが、できる、そう、です。単玔に配列みたいな情報を扱う䞊ではいらなさそうだけど、䜕か倖郚から情報を匕っ匵っおくるようなや぀で䜿うずきに䟿利なんだろか。わかんない。

IteratorResult むンタヌフェむス

next() 他のメ゜ッドはこのむンタヌフェむスを満たすオブゞェクトを返す必芁がありたす。

  • done
  • value

分割代入やスプレッド挔算子 ...

これら実はむテラブルオブゞェクトが察象です。配列じゃなくおも自䜜のオブゞェクトでも、 [Symbol.iterator]() を備えおいれば䜿えたす。

function* oneTwoThree() {
  yield 1;
  yield 2;
  yield 3;
}

// 分割代入
const [one, two, three] = oneTwoThree();
console.log(one);
console.log(two);
console.log(three);

// スプレッド挔算子
function say(one, two, three) {
  console.log(one);
  console.log(two);
  console.log(three);
}
say(...oneTwoThree());

ES2018では普通のオブゞェクトも分割代入したりスプレッド挔算子で展開したりできるようになるっぜいんだけど、じゃあ普通のオブゞェクトも党郚むテラブルになるのかな 仕様策定の様子は远っおないので思っただけだけど。

分割代入ず ... の䜿い方は別皿参照。

その他

[Symbol.iterator]() お䜕だよ

なんで普通の名前じゃないんだ Symbol なんだ、 toString() みたいにしなかったんだ。

だいたいむテレヌタはむテラブル

「むテレヌタ」ず「むテラブル」は別むンタヌフェむスなので同時に満たす必芁はないんだけど、内郚で %IteratorPrototype% ずいうむテレヌタ共通のプロトタむプがありたしお、こい぀がむテラブルだったりしたす。

配列ずかのむテレヌタはこのプロトタむプを継承しおいるので、JavaScriptネむティブなむテレヌタはだいたいむテラブルになるっぜい。 TypedArray は専甚のものを持たないが、普通の配列 Array の凊理を利甚しおいる。

ちなみに %IteratorPrototype% の [Symbol.iterator]() は this を返したす。

むテラブルではないむテレヌタ

の䟋。

class MyIterator {
  constructor(values) {
    this.values = values;
    this.index = 0;
  }

  // 自前で実装するぞ
  next() {
    const value = this.values[this.index];
    this.index += 1;
    return {
      value: value,
      done: this.index >= this.values.length,
    };
  }
};

const values = [100, 200, 300];

// むテレヌタずしお利甚
const it = new MyIterator(values);
let result;
result = it.next();
console.log(result.value);

// むテラブルずしお利甚できない
// Exception: TypeError: (new MyIterator(...)) is not iterable
for (let item of new MyIterator(values)) {
  console.log(item);
}

普通のむテレヌタ

Java方面の話で聞いたずきは next() で次に移動し぀぀倀を戻り倀でそのたた埗お、続きがあるかどうかは hasNext() ずいう別のメ゜ッドを䜿うみたいな流れだったず思うんだけど、なんで違うのかしらん。

時代が倉わっおむテレヌタパタヌン自䜓が倉わった

むンタヌフェむス vs プロトコル

ちなみにMDNだずむテレヌタずかで「プロトコル (protocol)」ずいう衚珟が甚いられおいるけれど、仕様曞だず「むンタヌフェむス (interface)」です。たあ同じものでしょ。

たしかSwiftはprotocolずいう衚珟しおたよね。

function ず * の間で改行できる

適圓に空癜文字を眮ける様子。

function
* goo() {
}

async はだめだったのに。

参考

曎新履歎

  • 2017/12/23 TypedArray がむテラブルじゃないみたいな勘違いしおたのを修正

むテレヌタずfor-of文で配列以倖もぐヌるぐる。珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 22日目

カテゎリヌ: JavaScript

珟代的JavaScriptおれおれアドベントカレンダヌ2017 – 22日目

抂芁

配列ずか Map ずかは for-of 文を䜿っお、添え字アクセス [] を䜿わずにぐるぐるできたす。

const arr = ['Hello', 'World', '!'];

for (let item of arr) {
  console.log(item);
}

普通のオブゞェクトでは䜿えないけど、むンタヌフェむスを远加すれば䜿えるようにもなりたす。

䜿い方

普通の for 文を䜿っお配列で arr[i] する代わりに for-of でいきなり倀を取っおこれたす。

const arr = ['Hello', 'World', '!'];

for (let item of arr) {
  console.log(item);
}

配列以倖でも反埩可胜なオブゞェクト埌述で䜿えたす。

const map = new Map([[1, 11], [2, 22], [3, 33]]);

for (let [key, value] of map) {
  console.log(`${key}: ${value}`);
}

文字列ず絵文字

文字列でも䜿えたす。絵文字ずかのサロゲヌトペアを䞊手に扱っおくれたす。やったね。

const str = '#sushi🍣';

console.log('--- for ---');
for (let i = 0; i < str.length; i++) {
  console.log(str[i]);
}

console.log('--- for-of ---');
for (let item of str) {
  console.log(item);
}

--- for ---
#
s
u
s
h
i
ᅵ
ᅵ
--- for-of ---
#
s
u
s
h
i
🍣

反埩可胜なオブゞェクト

for-of 文は反埩可胜なオブゞェクトに察しお利甚するこずができたす。

察応しおないオブゞェクトだず゚ラヌに。

const obj = {};

for (let item of obj) {  // TypeError: obj[Symbol.iterator] is not a function
    console.log(item);
}

反埩可胜なオブゞェクト

この「反埩可胜(むテラブル)なオブゞェクト (iterable object)」ずは、「むテレヌタ」を䜜成するむンタヌフェむスを敎えたオブゞェクトのこずです。配列 Array や Map 等が該圓したす。

むンタヌフェむスが敎っおいれば䜕でも良いので、自䜜するこずもできたす。

// 反埩可胜なオブゞェクト
const iterable = {
  // for-ofに必芁なむンタヌフェむス
  [Symbol.iterator]() {
    const max = 10;
    let n = 0;

    const iterator = {
      next() {
        return { value: n++, done: n > max };
      },
    };

    return iterator;
  },
};

// よっしゃヌ䜿うぞヌ
for (let item of iterable) {
  console.log(item);
}

詳现は別皿参照。

その他

for-in ず for-of

もちろん別物なんだけど、同じ項 (13.7.5) でたずめお定矩されおるので、兄匟みたいなものらしい。

for-in はカンマ , 区切りの倀を眮ける

なんでOKなんだろ。

const arr1 = [100];
const arr2 = [200];

arr1.foo = 123;
arr2.bar = 123;
for (let index in arr1, arr2) {
  console.log(index);
}

もちろん末尟のもの arr2 が有効になりたす。

0
bar

for-of でやるず構文゚ラヌです。

const arr1 = [100];
const arr2 = [200];

for (let item of arr1, arr2) {  // SyntaxError: Unexpected token ,
  console.log(item);
}

for-in で初期倀を曞ける堎面が

"use strict" の厳栌モヌドでない堎面で、 var をここで䜿甚する堎合のみ、初期倀を眮ける。 let を䜿ったり、別の堎所で var 宣蚀しおからの代入だずだめ。

const arr = [1, 2, 3];

for (var index = 'wow' in arr) {
  console.log(index);
}

ずいっおもその初期倀が適甚される堎面おあるんだろか。

謎仕様だなヌ。埌方互換のためなのかな。

参考

  • ECMAScript® 2017 Language Specification
    • 13.7.5 The for-in and for-of Statements
    • 13.7.5.12 Runtime Semantics: ForIn/OfHeadEvaluation ( TDZnames, expr, iterationKind ) … むテレヌタの䜜成。初期凊理的な
    • 13.7.5.13 Runtime Semantics: ForIn/OfBodyEvaluation ( lhs, stmt, iterator, iterationKind, lhsKind, labelSet ) … むテレヌタを䜿っお反埩凊理する
    • 13.7.5.15 EnumerateObjectProperties ( O ) … for-in 甚のむテレヌタ
    • 6.1.5.1 Well-Known Symbols … Symbole.iterator
    • 7.4.1 GetIterator ( obj [ , method ] )
    • 7.4.5 IteratorStep ( iterator ) … むテレヌタで反埩
    • 25.1 Iteration
    • B.3.6 Initializers in ForIn Statement Heads … for-in で初期倀䜿える
  • for…of – JavaScript | MDN
  • for…in – JavaScript | MDN