コンテンツにスキップ

8-3. 配列・オブジェクト・分割代入

  • 配列の基本操作と高階メソッド(mapfilterreduce など)を使いこなす
  • 破壊的メソッドと非破壊的メソッドの違いを理解する
  • オブジェクトの作成・操作・スプレッド構文によるマージを学ぶ
  • 分割代入(配列・オブジェクト・関数引数)で簡潔なコードを書けるようになる
  • JSONとJavaScriptオブジェクトの変換方法を理解する

const fruits = ["apple", "banana", "cherry"];
fruits[0] // "apple"
fruits.length // 3
fruits[fruits.length - 1] // "cherry"(最後の要素)
// 要素の追加・削除
fruits.push("date") // 末尾に追加 → ["apple", "banana", "cherry", "date"]
fruits.pop() // 末尾を削除して返す → "date"
fruits.unshift("avocado") // 先頭に追加
fruits.shift() // 先頭を削除して返す

高階メソッド(関数を受け取るメソッド)

Section titled “高階メソッド(関数を受け取るメソッド)”

配列の高階メソッドは現代のJavaScriptで最も頻繁に使われる機能のひとつだ。

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// forEach:各要素に対して順番に処理を実行する
numbers.forEach(n => console.log(n * 2));
// 2, 4, 6, 8, ...
// map:各要素を変換した新しい配列を返す
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
// filter:条件に合う要素だけを抽出した新しい配列を返す
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6, 8, 10]
// find:条件に最初に合う要素を返す(なければ undefined)
const firstBig = numbers.find(n => n > 5);
// 6
// some:少なくとも1つ条件を満たすか(boolean)
numbers.some(n => n > 9); // true
// every:全て条件を満たすか(boolean)
numbers.every(n => n > 0); // true
// reduce:配列を1つの値に集約する
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 55(初期値0から始めて順に足していく)
// メソッドチェーン(組み合わせる)
const result = numbers
.filter(n => n % 2 === 0) // 偶数だけ抽出
.map(n => n * n) // 二乗する
.reduce((acc, n) => acc + n, 0); // 合計
// 2²+4²+6²+8²+10² = 4+16+36+64+100 = 220
const arr = [3, 1, 4, 1, 5, 9, 2, 6];
// sort:破壊的ソート(元の配列が変わる)
arr.sort((a, b) => a - b); // 昇順:[1, 1, 2, 3, 4, 5, 6, 9]
arr.sort((a, b) => b - a); // 降順:[9, 6, 5, 4, 3, 2, 1, 1]
// slice:部分配列を取得(元の配列は変わらない)
[0, 1, 2, 3, 4].slice(1, 3) // [1, 2](index 1〜2)
[0, 1, 2, 3, 4].slice(-2) // [3, 4](末尾から2つ)
// flat:ネストした配列を平坦化
[1, [2, [3, [4]]]].flat() // [1, 2, [3, [4]]]
[1, [2, [3, [4]]]].flat(Infinity) // [1, 2, 3, 4]
// includes:要素が含まれるか
[1, 2, 3].includes(2) // true
// indexOf:要素の位置(なければ -1)
[1, 2, 3, 2].indexOf(2) // 1(最初のインデックス)
// join:配列を文字列に結合
["a", "b", "c"].join(", ") // "a, b, c"
// スプレッド構文:配列を展開して新しい配列を作る
const a = [1, 2, 3];
const b = [4, 5, 6];
const merged = [...a, ...b]; // [1, 2, 3, 4, 5, 6]
const copy = [...a]; // 浅いコピー

注意:破壊的メソッドと非破壊的メソッド

  • sortpushpopsplice は元の配列を変更する(破壊的)
  • mapfiltersliceconcat は新しい配列を返す(非破壊的)

破壊的メソッドは意図しない副作用を引き起こすことがある。配列のコピーを作ってから操作する習慣をつけよう。


const user = {
name: "Alice",
age: 30,
email: "alice@example.com",
isAdmin: false,
};
// プロパティへのアクセス
user.name // "Alice"(ドット記法)
user["email"] // "alice@example.com"(ブラケット記法)
// プロパティの追加・更新・削除
user.role = "editor"; // 追加
user.age = 31; // 更新
delete user.isAdmin; // 削除
// プロパティの存在確認
"name" in user // true
user.hasOwnProperty("name") // true

プロパティの省略記法とメソッド定義

Section titled “プロパティの省略記法とメソッド定義”
const name = "Bob";
const age = 25;
// 変数名とプロパティ名が同じなら省略できる
const user = {
name, // name: name と同じ
age, // age: age と同じ
greet() { // function キーワードを省略できる
return `こんにちは、${this.name}`;
},
};
const user = { name: "Alice", age: 30, role: "admin" };
// Object.keys:キーの配列
Object.keys(user) // ["name", "age", "role"]
// Object.values:値の配列
Object.values(user) // ["Alice", 30, "admin"]
// Object.entries:[キー, 値] のペア配列
Object.entries(user) // [["name", "Alice"], ["age", 30], ["role", "admin"]]
// Object.assign:オブジェクトをマージ(破壊的)
const base = { a: 1, b: 2 };
const extra = { b: 3, c: 4 };
Object.assign(base, extra); // base が { a: 1, b: 3, c: 4 } に変わる
// スプレッド構文によるマージ(非破壊的・推奨)
const merged = { ...base, ...extra }; // 元のオブジェクトは変わらない
// スプレッドはプロパティの上書きにも使える
const updated = { ...user, age: 31 }; // age だけ更新した新しいオブジェクト

分割代入を使うと、配列やオブジェクトから値を取り出して変数に代入するコードが簡潔になる。

const [first, second, third] = [10, 20, 30];
// first = 10, second = 20, third = 30
// 要素をスキップする
const [a, , c] = [1, 2, 3];
// a = 1, c = 3
// 残りをまとめて取得(残余要素)
const [head, ...tail] = [1, 2, 3, 4, 5];
// head = 1, tail = [2, 3, 4, 5]
// デフォルト値
const [x = 0, y = 0] = [10];
// x = 10, y = 0
// 変数の交換(分割代入を使うとスッキリ)
let p = 1, q = 2;
[p, q] = [q, p];
// p = 2, q = 1
const user = { name: "Alice", age: 30, role: "admin" };
const { name, age } = user;
// name = "Alice", age = 30
// 別名をつける
const { name: userName, role: userRole } = user;
// userName = "Alice", userRole = "admin"
// デフォルト値
const { name: n, email = "未設定" } = user;
// n = "Alice", email = "未設定"(userにemailプロパティがないため)
// ネストしたオブジェクト
const config = {
server: { host: "localhost", port: 3000 },
db: { host: "localhost", port: 5432 },
};
const { server: { host, port } } = config;
// host = "localhost", port = 3000

実務で最もよく使われるパターン。引数のオブジェクトを直接分割代入して受け取れる。

// 分割代入なしの場合
function createUser(options) {
const name = options.name;
const age = options.age;
const role = options.role || "user";
// ...
}
// 分割代入を使う(推奨)
function createUser({ name, age, role = "user" }) {
return { name, age, role };
}
createUser({ name: "Alice", age: 30 });
// { name: "Alice", age: 30, role: "user" }

JavaScriptのオブジェクトとJSONは見た目が似ているが別物だ。APIのレスポンスはJSON文字列として受け取り、JavaScriptのオブジェクトに変換して使う。

// オブジェクト → JSON文字列
const user = { name: "Alice", age: 30 };
const json = JSON.stringify(user);
// '{"name":"Alice","age":30}'
JSON.stringify(user, null, 2); // インデント付きで読みやすく出力
// {
// "name": "Alice",
// "age": 30
// }
// JSON文字列 → オブジェクト
const parsed = JSON.parse('{"name":"Alice","age":30}');
// { name: "Alice", age: 30 }
// 注意:JSONにできないもの
JSON.stringify(undefined) // undefined(文字列にならない)
JSON.stringify(function(){}) // undefined
JSON.stringify({ fn: function(){} }) // '{}'(関数プロパティは除外される)

項目ポイント
配列の高階メソッドforEachmapfilterreducefind を使いこなす
破壊的 vs 非破壊的sortpush は破壊的。mapfilter は非破壊的
オブジェクト操作スプレッド構文でコピー・マージするのが現代の主流
分割代入配列・オブジェクトから値を取り出す際に使う
JSONstringify(オブジェクト→文字列)と parse(文字列→オブジェクト)