keys と values と entries
このレッスンで分かること
- オブジェクトには
mapもfilterも無いので、いったん配列に変えますentriesが返すのは[キー, 値]の 2 要素配列なので、分割代入がそのまま効きます
配列のメソッドが 1 つも使えない
第2章では作品の配列を map と filter でつないできました。ところが、スキルごとの学習時間のように「キーそのものがデータ」である形は、オブジェクトで持つほうが自然です。
JavaScript
const hours = { HTML: 12, CSS: 8, JavaScript: 20 };
hours.map((value) => value * 2); // TypeError hours.map is not a functionオブジェクトには map も filter もありません。並び順という概念を持たないので、配列のメソッドが生えていないのは筋が通っています。そこで、いったん配列に変換します。
JavaScript
console.log(Object.keys(hours)); // ["HTML", "CSS", "JavaScript"]
console.log(Object.values(hours)); // [12, 8, 20]
console.log(Object.entries(hours)); // [["HTML", 12], ["CSS", 8], ["JavaScript", 20]]3 つとも Object に生えた関数で、引数にオブジェクトを渡します。hours.keys() のようにドットで呼ぶのではない点に気を付けてください。
| 関数 | 返るもの | 使いどころ |
|---|---|---|
Object.keys(obj) | キーの配列 | 件数を数える、一覧を出す |
Object.values(obj) | 値の配列 | 合計や最大値を求める |
Object.entries(obj) | [キー, 値] の配列 | キーと値の両方が要るとき |
Object.fromEntries(arr) | オブジェクト | 加工した結果を戻す |
[キー, 値] を分割代入で受ける
entries が返す 1 件は ["HTML", 12] という 2 要素の配列です。0 番目がキー、1 番目が値と位置が決まっているので、前のレッスンの配列の分割代入がそのまま効きます。
JavaScript
const labels = Object.entries(hours).map(([name, time]) => name + " " + time + " 時間");
console.log(labels); // ["HTML 12 時間", "CSS 8 時間", "JavaScript 20 時間"]
const long = Object.entries(hours).filter(([, time]) => time >= 10);
console.log(long.length); // 2([name, time]) => ... の内側の [] が分割代入です。entry[0] entry[1] と数字で書くより、何が入っているのかがはっきりします。キーが要らないときは [, time] と先頭をカンマだけで飛ばせます。見慣れないうちは戸惑いますが、「1 番目は要らない」という宣言です。
加工したらオブジェクトに戻す
Object.fromEntries は entries の逆向きです。配列にして加工し、元の形に戻します。
JavaScript
const doubled = Object.fromEntries(
Object.entries(hours).map(([name, time]) => [name, time * 2])
);
console.log(doubled); // { HTML: 24, CSS: 16, JavaScript: 40 }entries で開き、配列のメソッドで加工し、fromEntries で閉じる。この 3 段が、オブジェクトの中身を絞ったり書き換えたりするときの定石です。真ん中を map から filter に変えれば、条件に合うキーだけを残したオブジェクトが作れます。返しているのが [キー, 値] の 2 要素配列である点にだけ注意してください。
キーが必要になるかもしれないなら、最初から
entriesで開きます。valuesを使うのは、合計や最大値のようにキーを完全に捨ててよいときだけです。値だけ取って絞り込むと、残った数字がどの項目のものか分からなくなります。
よくある間違い
- ドットで呼ぼうとする —
hours.keys()はTypeErrorです。keysはオブジェクトのメソッドではなくObjectに生えた関数なので、Object.keys(hours)と書きます mapの中でオブジェクトを返す —fromEntriesが受け取れるのは 2 要素配列の並びです。({ name: time })のような形を返すと、意図した結果になりません
要件
- 関数名は summarizeViewCounts。引数はタイトルをキー、表示回数を値に持つオブジェクト 1 つ
- titles は Object.keys で取り出したタイトルの配列にする
- total は Object.values の合計にする。キーが 1 つも無いときは 0
- active は表示回数が 1 以上のものだけを残したオブジェクトにする。Object.entries と Object.fromEntries を使う
- 戻り値は { titles, total, active } のオブジェクト