2021年7月18日

Object.keys, values, entries

ここでは、個々のデータ構造から離れて、それらの繰り返し処理について話しましょう。

前のチャプターで、map.keys(), map.values(), map.entries() と言うメソッドを見ました。

これらのメソッドは一般的なものであり、データ構造に対して利用することは共通認識です。そのため、もし独自のデータ構造を作成するときには、それらも実装しておく方がよいです。

これらは以下でサポートされています:

  • Map
  • Set
  • Array

通常のオブジェクトも同様のメソッドをサポートしますが、構文は少し異なります。

Object.keys, values, entries

通常のオブジェクトでは、次のメソッドが使えます。:

しかし、それらの違いに注意してください(例として map との比較です。):

Map Object
構文 map.keys() Object.keys(obj). obj.keys() ではありません。
戻り値 iterable “本当の” Array

最初の違いは、obj.keys() ではなく、Object.keys(obj) と呼ぶ必要がある点です。

なぜそうなっているのでしょう?主な理由は柔軟性です。JavaScript ではオブジェクトはすべての複雑な構造のベースであることを忘れないでください。そのため、独自の order.values() メソッドを実装する order という独自のオブジェクトがあるかもしれません。それでも Object.values(order) を呼ぶことができます。

2つ目の違いは、Object.* メソッドが単なる iterable ではなく “本当の” 配列オブジェクトを返すことです。これは主に歴史的な理由です。

例:

let user = {
  name: "John",
  age: 30
};
  • Object.keys(user) = [name, age]
  • Object.values(user) = ["John", 30]
  • Object.entries(user) = [ ["name","John"], ["age",30] ]

ここの例では、Object.values を使って、プロパティの値をループします:

let user = {
  name: "John",
  age: 30
};

// 値のループ
for (let value of Object.values(user)) {
  alert(value); // John, そして 30
}
Object.keys/values/entries は Symbol プロパティを無視します

for..in ループのように、これらのメソッドはキーとして Symbol(...) を使っているプロパティを無視します。

通常それは便利です。しかし、もしもこのようなキーも同様に扱いたい場合は、別のメソッド Object.getOwnPropertySymbols があります。これは Symbol を使っているキーのみの配列を返します。また、メソッド Reflect.ownKeys(obj)すべての キーを返します。

オブジェクトの変換

オブジェクトには、配列に存在する多くのメソッドがありません。例えば map, filter など。

それらを適用したい場合は、Object.fromEntries に続いて、Object.entries が使用できます。:

  1. Object.entries(obj) を使用して obj からキー/値ペアの配列を取得します。
  2. その配列で、配列のメソッドを使用します。例えば map
  3. 結果の配列で Object.fromEntries(array) を使用して、配列をオブジェクトに戻します。

例えば、価格をもつオブジェクトがあり、それらを2倍したいとします。:

let prices = {
  banana: 1,
  orange: 2,
  meat: 4,
};

let doublePrices = Object.fromEntries(
  // 配列に変換して map を実行、その後 fromEntries でオブジェクトに戻します
  Object.entries(prices).map(([key, value]) => [key, value * 2])
);

alert(doublePrices.meat); // 8

一見難しく見えますが、1,2回使うと簡単に理解できます。このようにして協力な変換のチェーンを作ることができます。

タスク

重要性: 5

任意の数の給与を持つ salaries オブジェクトがあります。

Object.valuesfor..of ループを使ってすべての給与の合計を返す関数 sumSalaries(salaries) を書いてください。

もし salaries が空の場合、結果は 0 になります。

例:

let salaries = {
  "John": 100,
  "Pete": 300,
  "Mary": 250
};

alert( sumSalaries(salaries) ); // 650

テストと一緒にサンドボックスを開く

function sumSalaries(salaries) {

  let sum = 0;
  for (let salary of Object.values(salaries)) {
    sum += salary;
  }

  return sum;
}

サンドボックスでテストと一緒に解答を開く

重要性: 5

オブジェクトの中のプロパティの数を返す関数 count(obj) を書いてください。

let user = {
  name: 'John',
  age: 30
};

alert( count(user) ); // 2

できるだけ短いコードを作ってください。

P.S. シンボリックプロパティは無視し、“通常” のものだけをカウントしてください。

テストと一緒にサンドボックスを開く

function count(obj) {
  return Object.keys(obj).length;
}

サンドボックスでテストと一緒に解答を開く

チュートリアルマップ