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

reduce()はArrayにお最匷  おがえおおけ。配列ずかおれおれAdvent Calendar2018 – 23日目

カテゎリヌ: JavaScript

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

配列界最匷のメ゜ッドです。

たじ䟿利ずいうか䞇胜なので、ぜひご利甚頂きたい。

ちょっずわかりづらいんだけど、こんな↓感じです。

const arr = [11, 22, 33];

const obj = arr.reduce((acc, value, index) => {
  acc[`number${index}`] = value;
  return acc;
}, {});
console.log(obj);
// { number0: 11, number1: 22, number2: 33 }

䞎えたコヌルバック関数の次に第2匕数がある点に泚目。

むンタヌフェむスず䜿い方

result = arr.reduce(callback[, initialValue])
// callback = (accumulator, currentValue[, currentIndex, array]) => accumulator;

匕数

コヌルバック関数ず初期倀の2぀です。

第2匕数の初期倀に、䟋えばここに空のオブゞェクトを䞎えたりしたす。

第1匕数のコヌルバック関数が最初に受け取る第1匕数は、その初期倀になりたす。その倀を操䜜しお return するず、2回目以降のコヌルバック呌び出しの第1匕数にはその return した倀が䞎えられたす。

戻り倀

順に繰り返し、コヌルバック関数が最埌に return した倀が、 reduce() 党䜓の戻り倀になりたす。

初期倀をそのたた返しおみる䟋

initial がコヌルバック関数の第1匕数 acc ずしお䞎えられお、毎回それを return するので以降も同じむンスタンスを受け取り、最終的に結果もそれになりたす。

const arr = [11, 22, 33];

const initial = {};
const result = arr.reduce((acc, _, index) => {
  console.log(index, acc === initial);
  return acc;
}, initial);
console.log('result', result === initial);
// 0 true
// 1 true
// 2 true
// result true

初回だけ初期倀を受け取っおみる䟋

return 時に新しいむンスタンスを生成しおみたす。2回目はそれを受け取るので false 、たた新しいむンスタンスになっお3回目も同じく false です。

const arr = [11, 22, 33];

const initial = {};
const result = arr.reduce((acc, _, index) => {
  console.log(index, acc === initial);
  return { ...acc };
}, initial);
console.log('result', result === initial);
// 0 true
// 1 false
// 2 false
// result false

数倀を増やしおみる䟋

繰り返しながら操䜜する察象はオブゞェクトに限らず、このように数倀でも可胜です。

const arr = [11, 22, 33];

const result = arr.reduce((acc, _, index) => {
  console.log(index, acc);
  return acc + 1;
}, 100);
console.log('result', result);
// 0 100
// 1 101
// 2 102
// result 103

初期倀を省略した䟋

省略するず配列の最初の芁玠が䞎えられたす。たたコヌルバック関数はその次の芁玠から呌ばれたす。

この䟋↓だず最初 arr[0] の 11 がコヌルバック関数で凊理されず、最初から acc ぞ䞎えられたす。

const arr = [11, 22, 33];

const result = arr.reduce((acc, value, index) => {
  console.log(index, acc, value);
  return value;
});
console.log('result', result);
// 1 11 22
// 2 22 33
// result 33

䟋

合蚈

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sum = arr.reduce((acc, value) => acc + value);
console.log(sum); // => 55

最倧倀

Math.max(...arr) でやれるや぀。

const arr = [94, 39, 63, 87, 52, 3, 10, 95, 5];

const max = arr.reduce((acc, value) => (acc > value ? acc : value));
console.log(max); // => 95

マップ

map() 代わり。

const arr = [11, 22, 33];

const result = arr.reduce((acc, value, index) => {
  acc[index] = 1000 + value;
  return acc;
}, []);
console.log(result);
// [ 1011, 1022, 1033 ]

フィルタヌ

filter() 代わり。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const result = arr.reduce((acc, value) => {
  if (value % 3 === 0) {
    acc.push(value);
  }
  return acc;
}, []);
console.log(result);
// [ 3, 6, 9 ]

平坊化

flat() の代わり。

const arr = [
  11,
  [22, 33],
  44,
  [55, 66, 77],
];

const result = arr.reduce((acc, value) => acc.concat(value), []);
console.log(result);
// [ 11, 22, 33, 44, 55, 66, 77 ]

怜玢

find() 代わり。

const arr = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];

const result = arr.reduce((acc, value) => {
  if (acc) {
    return acc;
  }

  if (value.id === '102') {
    return value;
  }

  return undefined;
}, undefined);
console.log(result);
// { id: '102', name: 'Bob' }

同じようにしお some() 代替も䜜れる。

繰り返し

forEach() 代わり。

const arr = [11, 22, 33];

arr.reduce((_, value, index) => {
  console.log(index, value);
}, undefined);
// 0 11
// 1 22
// 2 33

初期倀を省略するず最初の芁玠が呌ばれない点に泚意。

IDでむンデックス

識別子を含むオブゞェクトの配列から、その識別子でアクセスできるオブゞェクトを䜜成したす。

const arr = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];

const map = arr.reduce((acc, record) => {
  acc[record.id] = record;
  return acc;
}, {});
console.log(map);
// { '101': { id: '101', name: 'Alice' },
//   '102': { id: '102', name: 'Bob' },
//   '103': { id: '103', name: 'Charlie' } }

オブゞェクトを耇補

{ ...obj } や Object.assign() の代わり。

const obj = {
  foo: 123,
  bar: {
    hoge: 234,
    fuga: {
      message: 'Yay!',
    },
  },
};

const obj2 = Object.entries(obj).reduce((acc, [key, value]) => {
  acc[key] = value;
  return acc;
}, {});
console.log(obj2);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }

reduce() より Object.entries() の方が良い仕事しおる気もする。

深いコピヌでオブゞェクトを耇補

const obj = {
  foo: 123,
  bar: {
    hoge: 234,
    fuga: {
      message: 'Yay!',
    },
  },
};

const deepCopy = (obj) => Object.entries(obj).reduce((acc, [key, value]) => {
  if (typeof value === 'object') {
    acc[key] = deepCopy(value);
  } else {
    acc[key] = value;
  }
  return acc;
}, {});

// 浅いコピヌ
const obj2 = { ...obj };
console.log(obj2);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }
console.log(obj2.bar === obj.bar);
// true

// 深いコピヌ
const obj3 = deepCopy(obj);
console.log(obj3);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }
console.log(obj3.bar === obj.bar);
// false

出珟芁玠数を数える

䜕でもいいいんだけど、詊しにHTML芁玠の芁玠名で。

const els = [...document.querySelectorAll('*')];
const counts = els.reduce((acc, el) => {
  const name = el.tagName.toLocaleLowerCase();
  if (!acc[name]) {
    acc[name] = 0;
  }
  acc[name] += 1;
  return acc;
}, {});
console.log(counts);
// Object { html: 1, head: 1, meta: 23, script: 12, title: 6, link: 32, body: 1, ul: 20, li: 186, a: 223, 
 }

クラス名ずかにしおもおもしろそう。

现かいずころ

仕様曞の説明

珍しく仕様曞にある説明が長いので、ちょっず芋おみたしょう。

Note 1

callbackfn should be a function that takes four arguments. reduce calls the callback, as a function, once for each element after the first element present in the array, in ascending order.

callbackfn is called with four arguments: the previousValue (value from the previous call to callbackfn), the currentValue (value of the current element), the currentIndex, and the object being traversed. The first time that callback is called, the previousValue and currentValue can be one of two values. If an initialValue was supplied in the call to reduce, then previousValue will be equal to initialValue and currentValue will be equal to the first value in the array. If no initialValue was supplied, then previousValue will be equal to the first value in the array and currentValue will be equal to the second. It is a TypeError if the array contains no elements and initialValue is not provided.

reduce does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

The range of elements processed by reduce is set before the first call to callbackfn. Elements that are appended to the array after the call to reduce begins will not be visited by callbackfn. If existing elements of the array are changed, their value as passed to callbackfn will be the value at the time reduce visits them; elements that are deleted after the call to reduce begins and before being visited are not visited.

ノヌト 1

callbackfn は4぀の匕数を取る関数になるだろう (should) 。 reduce はこのコヌルバックを、関数ずしお、配列に珟れる最初の芁玠以降の各芁玠ごずに、昇順で呌ぶ。

callbackfn は以䞋の4の匕数ずずもに呌ばれる: previousValue 前回の callbackfn 呌び出しで埗られる倀、 currentValue 珟圚の芁玠の倀、 currentIndex 、暪断䞭のオブゞェクト。最初にコヌルバック関数が呌ばれたずき、 previousValue ず currentValue は以䞋のいずれかになる。 reduce に initialValue が䞎えられた堎合、 previousValue は initialValue に等しくなり、 currentValue は配列の最初の倀ず等しくなる。 initialValue が䞎えられなかった堎合、 previousValue は配列の最初の倀ず等しくなり、 currentValue は2番目ず等しくなる。配列がひず぀も芁玠を持たず、か぀ initialValue も䞎えられなかった堎合、 TypeError になる。

reduce は呌ばれたオブゞェクトを盎接倉化させないが、そのオブゞェクトは callbackfn 呌び出しによっお倉化されおもよい (may) 。

reduce に凊理される芁玠の範囲は最初の callbackfn 呌び出しの前に蚭定される。最初の reduce 呌び出しが開始した埌に配列ぞ远加された芁玠は、 callbackfn から参照されるこずはない。配列の既存の芁玠が倉曎された堎合、 callbackfn ぞ䞎えられる倀は reduce がそれらを参照した時点での倀になる。たた、 reduce 呌び出しが始たった埌、参照より前に削陀された芁玠は、参照されない。

蚳泚: 関数が配列芁玠を visit するこずを「参照」ずしたした。

うっ日本語読みづら。

空の配列で゚ラヌ

配列の芁玠ひず぀以䞊あるいは初期倀を䞎えないず゚ラヌに。

[].reduce(() => {});
// TypeError: Reduce of empty array with no initial value

途䞭で远加された芁玠は呌ばれない

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    original.push(99);
  }
  console.log(index, value);
}, 0);
// 0 11
// 1 22
// 2 33

console.log(arr);
// [ 11, 22, 33, 99 ]

途䞭で倉曎された芁玠は倉曎埌の倀が利甚される

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    original[1] = 99;
  }
  console.log(index, value);
}, 0);
// 0 11
// 1 99
// 2 33

途䞭で削陀された芁玠は呌ばれない

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    delete original[1];
  }
  console.log(index, value);
}, 0);
// 0 11
// 2 33

途䞭じゃなくおも、削陀されお空き枠になっおいれば飛ばされたす。

空き枠は飛ばされる

たず空き枠、プロパティずしお存圚しない芁玠はコヌルバックで呌ばれたせん。これは他の繰り返し系配列メ゜ッドず同様。

加えお、初期倀を省略した堎合に埗られる倀も、空き枠を飛ばした最初の芁玠が呌ばれたす。

const arr = [, 22, 33,, 55];

arr.reduce((acc, value, index) => {
  console.log(acc, value, index);
  return acc;
});
// 22 33 2
// 22 55 4

初回コヌルバック関数呌び出し時の第1匕数 acc は普通 arr[0] になるんだけど、それが存圚しないので、代わりに最初に出珟する arr[1] の 22 になりたす。第2匕数 value はもちろんその次 33 。

たた 33 の次、 arr[3] もないので、それを飛ばしお2回目のコヌルバック関数呌び出しは arr[4] の 55 が value に䞎えられたす。

途䞭で終了できない

䟋倖投げるずかは別だけど、 for の break みたいな機胜はないです。

  1. Repeat, while k < len

存圚しないものを飛ばしながら単に繰り返すだけ。

その他

逆に回す reduceRight()

おのもありたす。

おしたい

ややこしいや぀だけど、倧倉䟿利なのでおがえおおくず䜕かず圹に立ちたす。

ちょっず読みづらいのが難点。

参考

空じゃないけど空の配列の話。配列ずかおれおれAdvent Calendar2018 – 22日目

カテゎリヌ: JavaScript

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

コンストラクタヌに芁玠数を䞎えるず、その「芁玠数」を持った配列が䜜られたす。しかし、「その数の芁玠」は持っおおらず、配列の䞭身が undefined すら入っおいない「空き枠」の状態になりたす。

const arr = new Array(3);
console.log(arr.length); // => 3
console.log(arr); // => [ <3 empty items> ]

䜜り方

コンストラクタヌ

さっきの。

const arr = new Array(3);

倧きなむンデックスで代入

arr.length を超えるむンデックスで倀を蚭定するず配列の倧きさが拡匵される、ず䞀般には衚珟されるんだけど、実際は length が曎新されるだけで該圓むンデックスに至る途䞭の枠は埋められず、空き枠になりたす。

const arr = [11, 22, 33];
delete arr[2];
console.log(arr.length); // => 3
console.log(arr); // => [ 11, 22, <1 empty item> ]

配列初期化子 []

倀為しでカンマ , を眮くこずで同様に空き枠を䌎う配列を䜜成するこずができたす。

const arr = [,, 1, , 2, ,,];
console.log(arr.length); // => 7
console.log(arr);
// => [ <2 empty items>, 1, <1 empty item>, 2, <2 empty items> ]

delete

普通のオブゞェクトプロパティず同様、 delete で配列の芁玠を削陀できたす。削陀埌は空き枠になりたす。

const arr = [11, 22, 33];
delete arr[1];
console.log(arr.length); // => 3
console.log(arr); // => [ 11, <1 empty item>, 33 ]

※ちなみに普通のオブゞェクトの堎合。

delete obj.foo;

空き枠にせず、削陀しお詰めたい堎合は splice() を䜿っおください。

仕組み

むンデックスはただのプロパティ名

たずJavaScript (ECMAScript) の配列こず Array むンスタンスは、䟋えばC蚀語のように実際に連続したメモリヌ領域ずしお存圚するわけではなく、JSの他のオブゞェクトず同様の仕組みです。俗にいうハッシュマップ。俗にね。

䟋えばオブゞェクトのプロパティは obj.foo ずしおアクセスできたすが、これは obj['foo'] ずも曞けたす。

逆に蚀えば arr[0] ずいうのも、 arr.0 ず同じようなものなのです。実際は .0 は䜿えないけど。

あ、埌述するけどむンデックスは数倀ではなく文字列です。 arr[0] は arr['0'] ぞ倉換されるず。

「圚る undefined 」ず「無い undefined 」

配列じゃない普通のオブゞェクトで、こういうのがあったずしたす。

const obj = {
  foo: undefined,
};
console.log(obj.foo); // => undefined
console.log(obj.bar); // => undefined

どちらも undefined だけど、前者 obj.foo はその䞭身が undefined ずしお存圚する䞀方で、埌者 obj.bar は存圚しないため undefined を埗たす。

埗られる倀は同じだけど動きが違いたすね。配列でもこれず同様のこずが起きおいるわけです。

配列颚オブゞェクトでそれっぜく曞きたす。

const obj = {
  0: 11,
  2: undefined,
  length: 3,
};

console.log(obj.length);// => 3
console.log(obj[1]);// => undefined
console.log(obj[2]);// => undefined

あるかないか確かめる

オブゞェクトがあるプロパティを持぀かどうかは、 in 挔算子を䜿っお調べるこずができたす。

const obj = {
  foo: undefined,
};
console.log('foo' in obj); // => true
console.log('bar' in obj); // => false

配列でも䜿える。

const arr = [11, , undefined];
console.log('2' in arr); // => true
console.log('1' in arr); // => false

空き枠で気を付けるこず

ただ undefined が挿入されおいる堎合ず䜕が違うかずいうず、配列芁玠を繰り返す系の倚くのメ゜ッドでコヌルバックが呌ばれたせん。

undefined が入っおる普通の配列

たず普通のや぀。これは期埅通りに動䜜する。

const arr = [undefined, undefined, undefined];
console.log('length :', arr.length);
// length : 3

arr.forEach((item, i) => {
  console.log(`[${i}] : ${item}`);
});
// [0] : undefined
// [1] : undefined
// [2] : undefined

const arr2 = arr.map((_, i) => i);
console.log(arr2);
// [ 0, 1, 2 ]

数だけあっお空の配列

undefined も入っおいない空き枠の堎合。

const arr = new Array(3);
console.log('length :', arr.length);
// length : 3

arr.forEach((item, i) => {
  console.log(`[${i}] : ${item}`); // <- これが実行されない
});

const arr2 = arr.map((_, i) => i);
console.log(arr2);
// [ <3 empty items> ]

呌ばれたせん。

呌ばれない機胜的理由

䟋えば forEach() の堎合、仕様はこのようになっおいたす。抜粋

  1. Let k be 0.
  2. Repeat, while k < len
    1. Let Pk be ! ToString(k).
    2. Let kPresent be ? HasProperty(O, Pk).
    3. If kPresent is true, then
      1. Let kValue be ? Get(O, Pk).
      2. Perform ? Call(callbackfn, T, « kValue, k, O »).
    4. Increase k by 1.

※匷調は匕甚者

匕甚蚻: 蚘述の郜合䞊、リスト項目先頭の数字が倉わっおいたす。

よくある for 文みたいな繰り返し方ですね。

問題はコヌルバック実行前の条件 “If kPresent is true” です。 HasProperty() を䜿っおプロパティキヌがあるか確認しおいたす。空き枠だずこの条件を満たせたせん。

呌ばれない思想的理由

わからないです。なんでだろね。

オブゞェクトで Object.entries() ずかしたら存圚しないものは圓然远加されないので、それに合わせたのかなあ。

空き枠ぞの察凊

自前で for を曞く

件の陀倖条件をわざわざ曞かなければ結果ずしお undefined を埗るだけなので、圓然 length 分動きたす。

コヌドはいらないよね。

空き枠を埋める

空き枠だけうたく埋める機胜っおないのでないよね、 in を䜿っお自力で埋める必芁がありそう。

const fillEmptySlots = (arr, value = undefined) => {
  for (let i = 0; i < arr.length; i++) {
    if (!(i in arr)) {
      arr[i] = value;
    }
  }
};

const arr = [11,, undefined];
fillEmptySlots(arr);
console.log(arr); // => [ 11, undefined, undefined ]

党おの枠を埋める

党おが空き枠の堎合、あるいは既存のものを無芖しおも良い堎合は、 fill() ずいうメ゜ッドがありたす。

const arr = [11,, undefined];
arr.fill();
console.log(arr); // => [ undefined, undefined, undefined ]

察象の配列を砎壊的に曎新されおたすね。

「党おが空き枠の堎合」ずしたが、匕数に開始䜍眮、終了䜍眮を受け付けるので、空き枠の範囲が明確な堎合でも利甚可胜。

そもそも空き枠を䜜らない

はいそうですね。

配列むンデックス

むンデックスは数倀ではなく文字列

ちらず觊れたけど、むンデックスは文字列です。もっずいうず「232 – 1未満の正の敎数を文字列にしたもの」です。

Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value. All String and Symbol values, including the empty string, are valid as property keys. A property name is a property key that is a String value.

An integer index is a String-valued property key that is a canonical numeric String (see 7.1.16) and whose numeric value is either +0 or a positive integer ≀ 253-1. An array index is an integer index whose numeric value i is in the range +0 ≀ i < 232-1.

プロパティはキヌ倀を甚いお特定される。プロパティのキヌ倀はECMAScriptのString倀かSymbol倀のいずれかである。あらゆるString及びSymbol倀空文字列を含むはプロパティキヌずしお劥圓 (valid) である。 property name ず蚀う堎合はString倀のキヌを指す。

integer index は正芏の数倀文字列 (a canonical numeric String) であるString倀プロパティキヌであり7.1.16を芋よ、その数的な倀 (numeric value) は +0 ないし正の敎数 ≀ 253-1 である。 array index は、その数的な倀 i が +0 ≀ i < 232-1 の範囲内ずなる integer index である。

i < 232-1

ぞヌちょっず詊しおみよう。

const arr = [];
arr[2 ** 32 - 2] = 0;
console.log(arr); // => [ <4294967294 empty items>, 0 ]
console.log(arr.length); // => 4294967295

arr[2 ** 32 - 1] = 0;
console.log(arr); // => [ <4294967294 empty items>, 0, '4294967295': 0 ]
console.log(arr.length); // => 4294967295

なるほど。

プロパティアクセス

いわゆる「配列の添え字アクセス」も、実際は党お文字列ぞ倉換され、普通のプロパティアクセスになりたす。

ちなみに foo.bar も foo['bar'] ぞ倉換されたす。

抜粋

The dot notation is explained by the following syntactic conversion:

MemberExpression . IdentifierName

is identical in its behaviour to

MemberExpression [ <identifier-name-string> ]

その他

名称

Firefoxのコン゜ヌルやMDNの䞀郚で “empty slots” ずいう衚珟を芋かけおそれ採甚しおたんだけど、䞀般的なんだろうか。

(Note: this implies an array of 7 empty slots, not slots with actual undefined values)

仕様䞭にそういう衚珟は芋぀からない。

日本語の「ある」ず「ない」

「有無」なんお熟語にもなるくらい察ずしお扱われるこい぀らだけど、「ある」は動詞なのに「ない」は圢容詞なんだよね。なんで動詞にならなかったんだろう ないものはないので動けないから

英語も「ある」が “exist” だけど「ない」に該圓する語はなさそう。文脈によっおは “absent” も䜿えるが圢容詞だ。 “lack” は動詞だけど、「欠ける」だずなんか違うよね。

おたけ: 各ブラりザヌでの空き枠の衚珟

次のコヌドをコン゜ヌルで実行した結果。

Array(3)

Chrome 71

(3) [empty × 3]

Firefox 64

Array(3) [ <3 empty slots> ]

Safari 12

[] (3) = $

最初の [] 以倖は文字色が薄くなっおたした。

Node.js v10

[ <3 empty items> ]

Edge (EdgeHTML 17)

[object Array]: [, , ]

IE 11

!!

[object Array][undefined, undefined, undefined]

forEach() のコヌルバックはちゃんず呌ばれたせんでした。良かった。

おしたい

ちなみにこれで困ったこずないです。でもい぀か匕っかかりそう。

関連

参考

曎新履歎

  • 2018-12-22 参考リンクをいく぀か远加
  • 2018-12-22 「プロパティアクセス」の説明があいたいだったのを修正

最初から分割代入するず曞くのが楜。配列ずかおれおれAdvent Calendar2018 – 21日目

カテゎリヌ: JavaScript

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

配列を分解しながら芁玠ごずに倉数ぞ代入するこずができたす。

const n = arr[0];
const m = arr[1];

↓

const [n, m] = arr;

䜿える堎所

  • 倉数の初期化let, const 宣蚀、代入
  • 関数匕数

できるこず

  • 必芁なものだけ受け取っお初期化、代入
  • 残䜙 ...
  • 初期倀 =

䜿い方

配列を分解しお倉数を䜜る

const arr = [11, 22, 33, 44, 55];
const [a, b, c, d, e] = arr;
console.log(a, b, c, d, e);

芁玠の省略

先頭や途䞭のものを飛ばす堎合、倉数を省略しおカンマ , だけ眮きたす。

const [ , b, , d, e] = arr;

末尟から飛ばす堎合は䜕も曞かなくお良い。

const [ , b, ,] = arr;

なんなら党郚飛ばしお [,,,] = arr みたいにも文法的には曞けたす。曞くこずないだろうけど。

入れ子

2次元配列の堎合、受け取り偎も2次元配列で衚珟するこずで、子配列の芁玠を盎接埗られたす。

const positions = [
  [11, 22],
  [33, 44],
];

const [
  [x1, y1],
  [x2, y2]
] = positions;
console.log(x1, y1, x2, y2);
// 11 22 33 44

もちろん2次元に限らず、N次元でいくらでも入れ子にできたす。

オブゞェクトの蚘法ず組み合わせるこずも可胜。

残䜙

... を䜿っお「残り党郚」を受け取れたす。

const [a, ...rest] = arr;

これも入れ子にしたり、オブゞェクトの蚘法ず組み合わせたりするこずができたす。

const arr = [11, 22, 33];
const [a, ...{ length }] = arr;
console.log(a, length);
// 11 2

倉数を䜿う方の堎面では逆にばらばらの倀ぞ展開するこずができたす。

初期倀

埗られた倀が undefined のずき、 = で指定した初期倀が倉数に栌玍されたす。基準は倀の有無ではなく undefined かどうかです。

const arr = [11, undefined];
const [a = -11, b = -22, c = -33] = arr;
console.log(a, b, c);
// 11 -22 -33

入れ子ず組み合わせるのもあり。

利甚可胜なもの

配列以倖でも、反埩可胜なものなら䜕でもいける。

const set = new Set([11, 22]);
const [a, b] = set;
console.log(a, b);
// 11 22
function* gen () {
  yield 11;
  yield 22;
  yield 33;
}

const [a, b, c] = gen();
console.log(a, b, c);
// 11 22 33

配列颚オブゞェクトはだめ

反埩可胜ではないので。

const obj = {
  0: 11,
  1: 22,
  2: 33,
  length: 3,
};
const [a, b, c] = obj;
console.log(a, b, c);

TypeError: obj is not iterable

関数匕数も分解や残䜙を䜿える

[a, b, c] の代わりに (a, b, c) 的な雰囲気で、同じように ... で「残り」を埗たり、 [] で分解しお受け取るこずができたす。

function* gen () {
  yield 11;
  yield 22;
  yield 33;
}

const f = ([a, ...rest]) => console.log(a, rest);
f(gen());
// 11 [ 22, 33 ]

arguments オブゞェクトがあるし、 (a, b, ...rest) を [a, b, ...rest] = arguments みたいに考えれば劥圓だよね。

利甚䟋

正芏衚珟でURLを分解

// 実務でご利甚の際は `match()` の結果が `null` になり埗る点をお忘れなく

const url = 'https://ginpei.info/path/to/file';

const matched = url.match(/(https?:)\/\/([\w.-]+)(.*)/);
const [ , protocol, host, path] = matched;
console.log('protocol:', protocol);
console.log('host:', host);
console.log('path:', path);
// protocol: https:
// host: ginpei.info
// path: /path/to/file

URLのパラメヌタヌを分解

const search = '?id=123&mode=fine'; // location.searchみたいな
const params = search
  .slice(1) // 冒頭 "?" を飛ばす
  .split('&')
  .reduce((map, pair) => {
    const [name, value] = pair.split('=');
    map[name] = value;
    return map;
  }, {});
console.log(params);
// => { id: '123', mode: 'fine' }

実際は items[]=a&items[]=b みたいな重耇したものにも察応が必芁かもね。

さらっず reduce() 䜿ったけど、䜕でもできる配列の最匷メ゜ッドです。

Object.entries() で

key-value組を分解するのにも䟿利。

const colors = {
  apple: 'red',
  banana: 'yellow',
  orange: 'orange',
};

Object.entries(colors).forEach(([name, color]) => {
  console.log(`${name} is ${color}`);
});

for-of でも

of の巊偎でも䜿えたす。

const colors = new Map();
colors.set('apple', 'red');
colors.set('banana', 'yellow');
colors.set('orange', 'orange');

for (const [name, color] of colors) {
  console.log(`${name} is ${color}`);
}

Promise.all() の結果で

耇数のAPIを䞊列に fetch() した結果ずか。

const [a, b] = await Promise.all([
  new Promise((resolve) => resolve('Hello')),
  new Promise((resolve) => resolve('World!')),
]);
console.log(a, b); // => Hello World!

コマンドを受け付ける

jQuery UIのや぀みたいに、第1匕数にコマンド名、以䞋コマンドに応じお0個以䞊のパラメヌタヌ、みたいな。

function exec (command, ...params) {
  switch (command) {
    // なんかする
  }
}

exec('start');
exec('say', 'Hello!');
exec('move', 10, 22);

残䜙匕数で受けるより、 params をオブゞェクトでたるっずもらう方が良さそうな気もする。

その他

残䜙匕数ず関数匕数の数

関数オブゞェクトは length プロパティを持っおいお、匕数の数が栌玍されおたす。残䜙匕数の堎合はそれに数えられたせん。

先のこの䟋↓だず、 f.length は 0 になりたす。

const f = (...args) => console.log(args);

ちなみに手元のEdge (EdgeHTML 17) だず 1 になりたした。ぞえ。

残䜙匕数の分解

結合しおからの分解。なんだこれ。

const f = (...[a, b]) => console.log(a, b);

前述の通り ... を䜿うず関数匕数の数 f.length に反映されないので、こっそり受け付けたいずきにこの組み合わせが䟿利ですね。嘘です、たぶんそんなこずする理由ない。

なお手元のEdge (EdgeHTML 17) だず動きたせんでした。関数匕数じゃなくお倉数の方は動く。

Object doesn't support property or method 'Symbol.iterator'

オブゞェクトの分割代入

同じようなもんです。 { ...rest } もある。

おしたい

ないならないでも曞けるんだけど、䜿えるず短くかけおすごく䟿利。

関連

参考

スプレッド挔算子  じゃなくお、スプレッド構文の䜿える堎所ずか䜿い方ずかそういう。配列ずかおれおれAdvent Calendar2018 – 20日目

カテゎリヌ: JavaScript

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

... を䜿うず配列から配列を䜜るのが簡単です。

const arr1 = [11, 22, 33];
const arr2 = [44, 55];

const arr3 = [...arr1, ...arr2];
console.log(arr3); // => [ 11, 22, 33, 44, 55 ]

const arr4 = [0, ...arr1, 0, ...arr2, 0];
console.log(arr4); // => [ 0, 11, 22, 33, 0, 44, 55, 0 ]

䜿い方

次の個所で利甚可胜です。

  • 配列初期化子 []
  • オブゞェクト初期化子 {}
  • 関数呌び出し時の匕数 ()
  • 分割代入 = 、関数の仮匕数 ()

配列初期化子 []

... に続けお反埩可胜 (iterable) なオブゞェクトを眮きたす。たあ普通は配列ですね。

const arr1 = [22, 33];
const arr2 = [55, 66];
const arr = [11, ...arr1, 44, ...arr2, 77];
console.log(arr);
// [ 11, 22, 33, 44, 55, 66, 77 ]

初期化䞭の配列芁玠ずしお ... を䌎ったものを芋぀けるず、内郚凊理 GetIterator() を通しお [Symbol.iterator]() メ゜ッドを甚いお反埩し、芁玠を远加したす。

反埩可胜オブゞェクト

反埩子を埗られれば動くので、必ずしも配列でなくおも構いたせん。

function* gen () {
  yield 11;
  yield 22;
  yield 33;
}

const it = gen();
const arr = [...it];
console.log(arr);
// [ 11, 22, 33 ]

オブゞェクト初期化子 {}

オブゞェクトも ... で耇補できたす。 Object.assign() よりらくちん。

const obj1 = { b: 22, c: 33 };
const obj2 = { e: 55, f: 66 };
const obj = { a: 11, ...obj1, d: 44, ...obj2, g: 77 };
console.log(obj);
// { a: 11, b: 22, c: 33, d: 44, e: 55, f: 66, g: 77 }

内郚凊理 CopyDataProperties() を甚いお ... 右のオブゞェクトのプロパティをコピヌしおいきたす。

玔粋オブゞェクト以倖も䜿えたす。

配列

䜿えたす。むンデックスがプロパティ名になりたす。

const arr1 = [11, 22];
const obj = { ...arr1 };
console.log(obj);
// { '0': 11, '1': 22 }

Symbol をプロパティ名に持぀オブゞェクト

䜿えたす。普通に耇補されたす。

const obj1 = { [Symbol('hey')]: 33 };
const obj = { ...obj1 };
console.log(obj);
// { [Symbol(hey)]: 33 }

継承しおきたプロパティ

は远加されたせん。

䜕か new しお䜜ったオブゞェクトで䜿える、 prototype から持っおきおる系メ゜ッドが远加されちゃったりしないわけですね。䟿利。

const obj1 = Object.create({ inherited: 11 });
obj1.own = 22;
console.log(obj1.inherited); // => 11
console.log(obj1.own); // => 22

const obj = { ...obj1 };
console.log(obj); // => { own: 22 }
console.log(obj.inherited); // => undefined

非オブゞェクト

無芖されたす。

const obj = { ...123 };
console.log(obj);
// {}

undefined か null の堎合、内郚凊理 CopyDataProperties() の過皋で単玔に無芖されたす。

それ以倖、真停倀、数倀、文字列、シンボルの堎合、内郚凊理 ToObject() を通しお察応するコンストラクタヌ䟋えば String の新芏オブゞェクトが䜜成されるんだけど、新しいオブゞェクトは圓然自身のプロパティを䞀切持っおいないので、䜕も远加されたせん。

ちなみに内郚凊理 ToObject() ぞ undefined か null を䞎えるず、 TypeError になっちゃう。

関数呌び出し時の匕数

関数を䜜る際ではなく呌び出す方ね。

const arr = [11, 22, 33];
const max = Math.max(...arr);
console.log(max); // => 33

配列初期化子 [] の ... ず同様、内郚凊理 GetIterator() を甚いお反埩、匕数リストを䜜成しお、関数呌び出しを実行したす。

仮匕数を ... で受け取っお、それをそのたた他の関数ぞパスする、みたいな䜿い方が良さそう

分割代入、関数の仮匕数

分解しお䞎えるんじゃなくお、䞎えられたものを分解し、か぀たずめお倉数の倀ずしお受け取るもの。

const cols = ['Taro', 'Yamada', 199, 99.9];
const [name, ...rest] = cols;
const exec = (cmd, ...options) => {}
exec('goStraight', 50);
exec('moveTo', 10, 20);

分割代入はたた埌日やりたす。

その他

「スプレッド挔算子」ではない

... は特定の曞匏でしか利甚できない構文 (syntax) の䞀郚です。

適圓な堎所で適圓に䜿うず構文゚ラヌになりたす。

const foo = [] + ...[];
// SyntaxError: Unexpected token ...

たあおれも去幎は「スプレッド挔算子」ず呌んでたけどね

あずMDNも前は「スプレッド挔算子」蚀っおたはず。気が付いたら倉わっおた。

「スプレッド構文」もない

実は ... を甚いた各皮構文の䞀郚であっお、 ... 単䜓には名前は付いおないみたいです。括匧 () に括匧 (parentheses) 以䞊の名前がないのず同様。

ただ配列初期化子 [] の構文においおは SpreadElement ずいう名前の、えヌず䜕おいうの、個所、で ... が利甚されおたす。ただこれも ... だけじゃなくお ...AssignmentExpression 党䜓で SpreadElement になるので、やっぱり ... 自䜓の名前はないですね。

実は仕様曞䞭にも “spread” ずいう単語はそんなに出おきおないです。

Chromeで仕様曞から怜玢した様子。
“spread” で怜玢しおヒットは37件のみ。

ずはいえ、英単語 spread が持぀雰囲気のひず぀は「折りたたたれたものを広げる」ずいう感じだそうなので、たあぎったりですね。MDNでも “Spread syntax” だし、他の人たちもそう呌んでるし、これでいいよね。IIFE即時実行関数みたいなもんか。そうか

仕様曞䞭ではあず他に、文法 (Grammar) の章で句読点 (punctuator) のひず぀ずしお玹介されおいるが。パヌザヌ䜜るずきに必芁な知識なのかな、よくわからない。

デフォルトコンストラクタヌ

継承はしたけどコンストラクタヌを甚意しおいないクラスでは、 ... を䜿ったこんなコンストラクタヌが自動的に甚意されるようです。

constructor(... args){ super (...args);}

なんかスペヌスの眮き方独特だな

concat() ず連結展開可胜性

単語 “spread” の数少ない出珟個所のひず぀に IsConcatSpreadable() ずいう内郚凊理がある。

配列の concat() からのみ呌ばれる内郚凊理。

concat() はこの内郚凊理を利甚しお、プロパティ [Symbol.isConcatSpreadable] を参照しお、 true であれば、匷制的に配列ずみなしお展開、察象配列ぞ連結するずいうもの。逆に false であれば匷制的に展開なしに連結したす。初期倀はないので普通は undefined で、その堎合は配列かどうかで刀断されたす。

䟋ずしお、たずは配列颚のオブゞェクト。配列ではないので、オブゞェクト䞞ごずが芁玠になりたす。

const obj = {
  0: 11,
  1: 22,
  2: 33,
  length: 3,
};
const arr = [0];
const arr2 = arr.concat(obj);
console.log(arr2);
// [ 0, { '0': 11, '1': 22, '2': 33, length: 3 } ]

続いお [Symbol.isConcatSpreadable] を蚭定したもの。無事、本物の配列のように連結されたした。

const obj = {
  0: 11,
  1: 22,
  2: 33,
  length: 3,
  [Symbol.isConcatSpreadable]: true,
};
const arr = [0];
const arr2 = arr.concat(obj);
console.log(arr2);
// [ 0, 11, 22, 33 ]

逆に普通の配列むンスタンスで [Symbol.isConcatSpreadable] に false を蚭定するず、展開されず配列䞞ごずが察象配列の芁玠になりたす。二重配列。

スプレッド構文関係ないけど、せっかくなのでここで。

おしたい

そこたで ... を頻繁に䜿うかずいうずそうでもない気もするんだけど、でもこれがあるずめっちゃ楜になる堎面があるので、この仕様䜜っおくれたひずありがずう、ずいう気持ちです。

関連

参考

反埩凊理の䞭身、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 おな感じみたい。

おしたい

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

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

関連

参考