T-CREATOR

JavaScript のオブジェクト操作まとめ:Object.keys/entries/values の使い方

JavaScript のオブジェクト操作まとめ:Object.keys/entries/values の使い方

JavaScript でオブジェクトの操作は日常的な作業です。Object.keys、Object.entries、Object.values の 3 つのメソッドを使いこなすことで、より効率的なコード記述が可能になります。

特に、配列操作のように map や filter を使いたい場面や、オブジェクトの構造を変更したい場面で、これらのメソッドは威力を発揮します。ES2017 で標準化されたこれらの機能を使って、モダンな JavaScript 開発をスムーズに進めましょう。

背景

オブジェクト操作の重要性

JavaScript において、オブジェクトはデータ構造の基本となる重要な要素です。API からのレスポンス、設定オブジェクト、ユーザーデータなど、あらゆる場面でオブジェクトを扱う必要があります。

しかし、配列と異なり、オブジェクトには map や filter のような便利なメソッドが存在しませんでした。そのため、開発者はオブジェクトの処理に for...in ループや Object.getOwnPropertyNames() などの複雑な手法を使わざるを得なかったのです。

以下の図は、JavaScript におけるオブジェクト操作の重要性を示しています。

mermaidflowchart TD
    data[データ取得] --> api[API レスポンス]
    data --> form[フォーム入力]
    data --> config[設定ファイル]

    api --> obj[JavaScript オブジェクト]
    form --> obj
    config --> obj

    obj --> process[データ処理]
    process --> display[画面表示]
    process --> validation[バリデーション]
    process --> storage[データ保存]

図で理解できる要点:

  • あらゆるデータソースがオブジェクト形式で JavaScript に取り込まれます
  • オブジェクト操作は JavaScript 開発の中核的な作業です
  • 効率的なオブジェクト操作により、コード品質と開発速度が向上します

ES2017 で追加された便利なメソッド群

ES2017(ES8)では、オブジェクト操作を大幅に簡素化する 3 つのメソッドが追加されました。

メソッド戻り値用途
Object.keys()キーの配列オブジェクトのプロパティ名を取得
Object.values()値の配列オブジェクトの値のみを取得
Object.entries()[キー, 値] ペアの配列キーと値を同時に取得

これらのメソッドは、関数型プログラミングのパラダイムを JavaScript に持ち込み、より宣言的で読みやすいコードの記述を可能にしました。

従来の for...in ループとの違い

従来の for...in ループと新しいメソッド群の違いを理解することで、適切な使い分けができるようになります。

for...in ループの問題点を示すコード例:

javascriptconst user = { name: 'Alice', age: 30, city: 'Tokyo' };

// 従来の方法
const keys = [];
for (let key in user) {
  if (user.hasOwnProperty(key)) {
    keys.push(key);
  }
}
console.log(keys); // ['name', 'age', 'city']

hasOwnProperty() チェックが必要で、コードが冗長になってしまいます。

ES2017 のメソッドを使用した場合:

javascriptconst user = { name: 'Alice', age: 30, city: 'Tokyo' };

// ES2017 の方法
const keys = Object.keys(user);
console.log(keys); // ['name', 'age', 'city']

シンプルで直感的なコードになり、意図も明確に伝わります。

課題

オブジェクトの各要素にアクセスする際の問題点

JavaScript 開発において、オブジェクト操作で頻繁に発生する課題があります。

配列のような操作ができない問題:

javascriptconst products = {
  laptop: 1200,
  mouse: 30,
  keyboard: 80,
};

// 配列なら簡単にできること
// products.map(price => price * 1.1) // エラー!

オブジェクトには map メソッドが存在しないため、値の変換処理が困難でした。

キーと値の同時取得が複雑な問題:

javascriptconst settings = {
  theme: 'dark',
  language: 'ja',
  notifications: true,
};

// 従来の方法:キーと値を同時に扱うのが煩雑
for (let key in settings) {
  console.log(`${key}: ${settings[key]}`);
}

パフォーマンスと可読性の両立

効率的なオブジェクト操作では、パフォーマンスと可読性の両方を考慮する必要があります。

パフォーマンスの課題:

javascriptconst largeObject = {
  /* 数千のプロパティ */
};

// 非効率なアプローチ
Object.keys(largeObject).forEach((key) => {
  const value = largeObject[key]; // 毎回プロパティアクセス
  // 処理...
});

可読性の課題:

javascript// 意図が伝わりにくいコード
const result = {};
for (let key in data) {
  if (data[key] > threshold) {
    result[key] = data[key] * multiplier;
  }
}

型安全性の確保

TypeScript を使用する場合、オブジェクト操作で型安全性を保つことが重要です。

型安全性の問題例:

typescriptinterface User {
  name: string;
  age: number;
  email: string;
}

const user: User = {
  name: 'Bob',
  age: 25,
  email: 'bob@example.com',
};

// Object.keys() の戻り値は string[] なので型情報が失われる
Object.keys(user).forEach((key) => {
  // TypeScript エラー:key が User のキーであることが保証されない
  console.log(user[key]);
});

解決策

Object.keys() の基本的な使い方

Object.keys() は、オブジェクトの列挙可能なプロパティ名を配列として返します。

基本的な使用方法:

javascriptconst person = {
  firstName: 'John',
  lastName: 'Doe',
  age: 30,
};

const keys = Object.keys(person);
console.log(keys); // ['firstName', 'lastName', 'age']

配列メソッドとの組み合わせ:

javascriptconst config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retryCount: 3,
};

// 特定の条件に合うキーのフィルタリング
const timeoutKeys = Object.keys(config).filter((key) =>
  key.includes('timeout')
);
console.log(timeoutKeys); // ['timeout']

動的なプロパティアクセス:

javascriptconst data = {
  user_name: 'alice',
  user_email: 'alice@example.com',
  user_age: 28,
};

// キーの変換処理
const transformedKeys = Object.keys(data).map((key) =>
  key.replace('user_', '')
);
console.log(transformedKeys); // ['name', 'email', 'age']

Object.entries() によるキー・値のペア操作

Object.entries() は、オブジェクトのキーと値のペアを [key, value] 形式の配列として返します。

基本的な使用方法:

javascriptconst scores = {
  math: 85,
  english: 92,
  science: 78,
};

const entries = Object.entries(scores);
console.log(entries);
// [['math', 85], ['english', 92], ['science', 78]]

キーと値の同時処理:

javascriptconst prices = {
  apple: 100,
  banana: 80,
  orange: 120,
};

// 税込み価格の計算
Object.entries(prices).forEach(([item, price]) => {
  const taxIncluded = Math.floor(price * 1.1);
  console.log(`${item}: ${taxIncluded}円`);
});

オブジェクトの変換処理:

javascriptconst userData = {
  name: 'Charlie',
  age: 35,
  city: 'Osaka',
};

// 新しいオブジェクトの生成
const upperCaseData = Object.fromEntries(
  Object.entries(userData).map(([key, value]) => [
    key.toUpperCase(),
    typeof value === 'string' ? value.toUpperCase() : value,
  ])
);
console.log(upperCaseData);
// { NAME: 'CHARLIE', AGE: 35, CITY: 'OSAKA' }

Object.values() での値の取得方法

Object.values() は、オブジェクトの値のみを配列として返します。

基本的な使用方法:

javascriptconst inventory = {
  laptops: 15,
  mice: 200,
  keyboards: 50,
};

const quantities = Object.values(inventory);
console.log(quantities); // [15, 200, 50]

値に対する集計処理:

javascriptconst sales = {
  january: 150000,
  february: 180000,
  march: 220000,
};

// 合計売上の計算
const totalSales = Object.values(sales).reduce(
  (sum, amount) => sum + amount,
  0
);
console.log(`総売上: ${totalSales}円`); // 総売上: 550000円

値の検証処理:

javascriptconst formData = {
  username: 'testuser',
  password: 'securepass123',
  email: 'test@example.com',
};

// すべての値が入力されているかチェック
const allFieldsFilled = Object.values(formData).every(
  (value) => value && value.length > 0
);
console.log(`入力完了: ${allFieldsFilled}`); // 入力完了: true

3 つのメソッドの使い分け指針

適切なメソッドの選択により、コードの意図を明確に表現できます。

以下の図は、3 つのメソッドの使い分けを示しています。

mermaidflowchart TD
    start["オブジェクト操作の必要性"] --> question{"何が必要?"};

    question -->|キーのみ| keys["Object.keys()"];
    question -->|値のみ| values["Object.values()"];
    question -->|キーと値の両方| entries["Object.entries()"];

    keys --> keys_use["プロパティ名の操作<br/>動的アクセス<br/>キーの変換"];
    values --> values_use["値の集計<br/>検証処理<br/>配列操作"];
    entries --> entries_use["オブジェクト変換<br/>ペア処理<br/>新オブジェクト生成"];

図で理解できる要点:

  • キーのみが必要な場合は Object.keys() を使用
  • 値のみで十分な場合は Object.values() を選択
  • キーと値の両方が必要な場合は Object.entries() が最適

使い分けの実例:

javascriptconst userStats = {
  posts: 50,
  followers: 120,
  following: 80,
};

// キーのみが必要:メニュー項目の生成
const menuItems = Object.keys(userStats);

// 値のみが必要:統計情報の合計
const totalActivity = Object.values(userStats).reduce(
  (sum, count) => sum + count,
  0
);

// キーと値の両方が必要:表示用フォーマット
const displayStats = Object.entries(userStats)
  .map(([key, value]) => `${key}: ${value}`)
  .join(', ');

具体例

実際のデータ処理での活用

実際の開発現場でよくある、API レスポンスの処理例をご紹介します。

API から取得したユーザーデータの処理:

javascript// API レスポンス(模擬データ)
const apiResponse = {
  user_id: 12345,
  user_name: 'developer',
  user_email: 'dev@example.com',
  user_status: 'active',
  last_login: '2023-12-01',
};

Object.keys() を使用したキーの正規化:

javascript// プレフィックスの削除
const normalizedUser = {};
Object.keys(apiResponse).forEach((key) => {
  const newKey = key.replace('user_', '');
  normalizedUser[newKey] = apiResponse[key];
});

console.log(normalizedUser);
// { id: 12345, name: 'developer', email: 'dev@example.com', status: 'active', last_login: '2023-12-01' }

Object.entries() を使用したより効率的な変換:

javascriptconst transformedUser = Object.fromEntries(
  Object.entries(apiResponse).map(([key, value]) => [
    key.replace('user_', ''),
    value,
  ])
);

データの検証処理:

javascriptconst requiredFields = ['user_name', 'user_email'];

// 必須フィールドの存在確認
const hasRequiredFields = requiredFields.every((field) =>
  Object.keys(apiResponse).includes(field)
);

// 必須フィールドの値の妥当性確認
const hasValidValues = Object.values(apiResponse)
  .filter((_, index) =>
    requiredFields.includes(Object.keys(apiResponse)[index])
  )
  .every((value) => value && value.toString().length > 0);

React コンポーネントでの利用例

React 開発における実践的な活用例をご紹介します。

フォームの状態管理:

javascriptimport { useState } from 'react';

function UserForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    phone: ''
  });

  const [errors, setErrors] = useState({});

  // Object.keys()を使用したフィールドのクリア
  const clearForm = () => {
    const clearedData = Object.keys(formData).reduce((acc, key) => {
      acc[key] = '';
      return acc;
    }, {});
    setFormData(clearedData);
  };

Object.entries() を使用した動的フォームレンダリング:

javascriptconst renderFormFields = () => {
  return Object.entries(formData).map(
    ([fieldName, value]) => (
      <div key={fieldName}>
        <label htmlFor={fieldName}>
          {fieldName.charAt(0).toUpperCase() +
            fieldName.slice(1)}
          :
        </label>
        <input
          id={fieldName}
          type='text'
          value={value}
          onChange={(e) =>
            setFormData((prev) => ({
              ...prev,
              [fieldName]: e.target.value,
            }))
          }
        />
      </div>
    )
  );
};

Object.values() を使用したバリデーション:

javascript  // フォーム送信時の検証
  const handleSubmit = (e) => {
    e.preventDefault();

    // すべてのフィールドが入力されているかチェック
    const allFieldsFilled = Object.values(formData)
      .every(value => value.trim().length > 0);

    if (!allFieldsFilled) {
      alert('すべてのフィールドを入力してください');
      return;
    }

    // フォーム送信処理...
  };

  return (
    <form onSubmit={handleSubmit}>
      {renderFormFields()}
      <button type="submit">送信</button>
      <button type="button" onClick={clearForm}>クリア</button>
    </form>
  );
}

API レスポンスの変換処理

API からのデータを画面表示用に変換する際の実例です。

商品データの変換処理:

javascript// API レスポンス
const productsResponse = {
  electronics: { count: 150, revenue: 500000 },
  clothing: { count: 89, revenue: 120000 },
  books: { count: 234, revenue: 78000 },
};

Object.entries() を使用したテーブルデータの生成:

javascriptconst tableData = Object.entries(productsResponse).map(
  ([category, data]) => ({
    category: category,
    itemCount: data.count,
    totalRevenue: data.revenue,
    averagePrice: Math.round(data.revenue / data.count),
  })
);

console.log(tableData);
// [
//   { category: 'electronics', itemCount: 150, totalRevenue: 500000, averagePrice: 3333 },
//   { category: 'clothing', itemCount: 89, totalRevenue: 120000, averagePrice: 1348 },
//   { category: 'books', itemCount: 234, totalRevenue: 78000, averagePrice: 333 }
// ]

Object.values() を使用した集計処理:

javascript// 全カテゴリの合計データ
const totalStats = Object.values(productsResponse).reduce(
  (totals, categoryData) => ({
    totalItems: totals.totalItems + categoryData.count,
    totalRevenue:
      totals.totalRevenue + categoryData.revenue,
  }),
  { totalItems: 0, totalRevenue: 0 }
);

console.log(totalStats);
// { totalItems: 473, totalRevenue: 698000 }

フォームデータの検証

実際のフォームバリデーションでの活用例をご紹介します。

複雑なバリデーションルールの実装:

javascriptconst validationRules = {
  email: (value) =>
    /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
  phone: (value) =>
    /^\d{10,11}$/.test(value.replace(/[^\d]/g, '')),
  name: (value) => value.length >= 2 && value.length <= 50,
  age: (value) => value >= 18 && value <= 100,
};

const formData = {
  email: 'user@example.com',
  phone: '090-1234-5678',
  name: 'Test User',
  age: 25,
};

Object.entries() を使用したバリデーション実行:

javascriptconst validateForm = (data, rules) => {
  const validationResults = Object.entries(rules).map(
    ([field, validator]) => {
      const value = data[field];
      const isValid =
        value !== undefined && validator(value);

      return {
        field,
        value,
        isValid,
        error: isValid
          ? null
          : `${field} の形式が正しくありません`,
      };
    }
  );

  return validationResults;
};

const results = validateForm(formData, validationRules);
console.log(results);

Object.keys() を使用したエラーフィールドの特定:

javascriptconst getErrorFields = (validationResults) => {
  return validationResults
    .filter((result) => !result.isValid)
    .map((result) => result.field);
};

const errorFields = getErrorFields(results);
if (errorFields.length > 0) {
  console.log(
    `エラーのあるフィールド: ${errorFields.join(', ')}`
  );
}

Object.values() を使用した全体の妥当性確認:

javascriptconst isFormValid = (validationResults) => {
  return validationResults.every(
    (result) => result.isValid
  );
};

const formIsValid = isFormValid(results);
console.log(`フォームは有効: ${formIsValid}`);

まとめ

Object.keys、Object.entries、Object.values の 3 つのメソッドを使いこなすことで、JavaScript のオブジェクト操作が格段に効率的になります。

これらのメソッドの特徴をまとめると以下のようになります:

メソッド戻り値主な用途パフォーマンス
Object.keys()string[]プロパティ名の操作、動的アクセス高速
Object.values()any[]値の集計、検証処理高速
Object.entries()[string, any][]オブジェクト変換、ペア処理中程度

ES2017 で導入されたこれらの機能により、従来の for...in ループや複雑な処理が不要になり、より宣言的で読みやすいコードが書けるようになりました。

特に以下の場面では、これらのメソッドの威力を実感できるでしょう:

  • API レスポンスの変換処理
  • React での動的フォーム生成
  • データの集計や検証
  • オブジェクトの構造変換

モダンな JavaScript 開発において、これらのメソッドは必須のスキルです。適切な使い分けを心がけて、効率的なコード作成を目指しましょう。

関連リンク