さようなら $.each() – 配列操作のモダンな書き方

「配列の中身を処理するのに、いつも$.each()使ってるけど、他の方法があるって聞いた…」 「mapとかfilterとか出てくるけど、どう使い分ければいいの?」 「そもそもこれらの新しいメソッドって、どんなメリットがあるの?」

前回は変数宣言のlet/constについて解説しました。今回は、jQueryの$.each()から、モダンJavaScriptの配列メソッドへの移行を見ていきましょう。これらのメソッドを使いこなすことで、より意図が明確で保守性の高いコードが書けるようになります。

なぜ$.each()から移行するのか?

まずは従来のjQueryでの配列操作を見てみましょう:

JS
// jQueryでの配列操作
var users = [
    { id: 1, name: "John", age: 25 },
    { id: 2, name: "Jane", age: 30 },
    { id: 3, name: "Bob", age: 20 }
];

// 名前の配列を作成
var names = [];
$.each(users, function(index, user) {
    names.push(user.name);
});

// 20歳以上のユーザーを抽出
var adults = [];
$.each(users, function(index, user) {
    if (user.age >= 20) {
        adults.push(user);
    }
});

// 年齢の合計を計算
var totalAge = 0;
$.each(users, function(index, user) {
    totalAge += user.age;
});

このコードには以下の問題があります:

  1. 中間配列の作成が必要
  2. 処理の意図が分かりにくい
  3. チェーンが困難
  4. 余分なインデックス引数

モダンな配列メソッドの基本

JavaScriptには、目的に応じた様々な配列メソッドが用意されています:

JS
const users = [
    { id: 1, name: "John", age: 25 },
    { id: 2, name: "Jane", age: 30 },
    { id: 3, name: "Bob", age: 20 }
];

// map: 配列の各要素を変換
const names = users.map(user => user.name);

// filter: 条件に合う要素を抽出
const adults = users.filter(user => user.age >= 20);

// reduce: 値を集約
const totalAge = users.reduce((sum, user) => sum + user.age, 0);

主要な配列メソッドの使い分け

1.map(): 変換

JS
// Before: jQuery
var prices = [];
$.each(products, function(index, product) {
    prices.push(product.price);
});

// After: Modern JavaScript
const prices = products.map(product => product.price);

2.filter(): 抽出

JS
// Before: jQuery
var activeUsers = [];
$.each(users, function(index, user) {
    if (user.isActive) {
        activeUsers.push(user);
    }
});

// After: Modern JavaScript
const activeUsers = users.filter(user => user.isActive);

3.reduce(): 集約

JS
// Before: jQuery
var total = 0;
$.each(items, function(index, item) {
    total += item.quantity * item.price;
});

// After: Modern JavaScript
const total = items.reduce(
    (sum, item) => sum + item.quantity * item.price, 
    0
);

4.find(): 要素の検索

JS
// Before: jQuery
var targetUser = null;
$.each(users, function(index, user) {
    if (user.id === targetId) {
        targetUser = user;
        return false; // ループを抜ける
    }
});

// After: Modern JavaScript
const targetUser = users.find(user => user.id === targetId);

メソッドチェーンで処理を組み合わせる

モダンな配列メソッドの大きな特徴は、チェーンで処理を組み合わせられることです:

JS
const result = users
    .filter(user => user.age >= 20)
    .map(user => ({
        fullName: `${user.firstName} ${user.lastName}`,
        age: user.age
    }))
    .sort((a, b) => a.age - b.age);

実践的なリファクタリング例

実際のjQueryコードをモダンな書き方に変更してみましょう:

JS
// Before: jQuery
var $userList = $('#userList');
var activeUsers = [];

$.each(users, function(index, user) {
    if (user.isActive) {
        activeUsers.push(user);
    }
});

$.each(activeUsers, function(index, user) {
    var $li = $('<li>')
        .addClass('user-item')
        .text(user.name);
    $userList.append($li);
});

// After: Modern JavaScript
const userList = document.querySelector('#userList');
const activeUsers = users
    .filter(user => user.isActive)
    .map(user => `<li class="user-item">${user.name}</li>`)
    .join('');

userList.innerHTML = activeUsers;

パフォーマンスと注意点

1.早期リターン

JS
// findは条件に合致したら処理を停止
const user = users.find(user => user.id === targetId);

// someは存在確認に最適
const hasAdmin = users.some(user => user.role === 'admin');

2.不要なチェーンを避ける

JS
// Bad: 無駄な中間配列が作られる
const result = users
    .map(user => user.age)
    .filter(age => age >= 20)
    .map(age => age * 2);

// Good: 1回のループで処理
const result = users
    .reduce((acc, user) => {
        if (user.age >= 20) {
            acc.push(user.age * 2);
        }
        return acc;
    }, []);

まとめ

モダンな配列メソッドを使うことで:

  • コードの意図がより明確に
  • 中間変数が不要に
  • 処理の組み合わせが容易に
  • メンテナンス性が向上

という効果が得られます。次回は「テンプレートリテラルでHTML生成を最適化」について解説し、さらに表現力豊かなコードの書き方を学んでいきましょう。