0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

業務でレガシーなシステム(jQuery 1.x系など)のメンテナンスをしていると、「条件分岐が複雑すぎて読めない」「値は画面上と合っているはずなのに、なぜか if 文の判定をすり抜ける」といった壁にぶつかることがよくあります。

今回は、実務のコードレビューやリファクタリングで特に効果の高かった「可読性を爆上げする設計」「jQuery特有のデータの罠」について、初心者向けに分かりやすく解説します!


1. 読めない if (!A || !B) からの脱却!「エラー検知型」リファクタリング

🚨 よくある「アンチパターン」

フォームのバリデーションなどで、以下のように「関数が正常(true)に終わらなかったらエラー」という条件式をよく見かけます。

// 【アンチパターン】
// プランが変更可能か、変更不可の選択肢が外されていないか、カテゴリ名が変更されているか
if (!_self.validatePlanBeforeSubmit() || !_self.validateLockedOptionsBeforeSubmit() || _self.hasChangedCategoryValues()) {
    alert("変更できない値が含まれています");
    return false;
}

何が辛いのか?

  • !(否定)と ||(または)が組み合わさることで、「何が成功で、何が失敗(エラー)のときにアラートが出るのか」が一瞬で脳内変換できません。
  • !validate() という「成功の否定」は、チェック項目が増えるほど仕様変更の際にバグの温床になります。

💡 改善策:主語を「エラー(異常)があるか?」に変える

関数自体の役割を「バリデーション(成功か?)」から 「エラー検知(異常があるか?)」 に180度変えてみましょう。

// 1. 各チェック関数を「エラーなら true」を返すように定義
hasErrorPlanChange: function () {
    var isUnsetSelected = $('#plan_setting_unset').prop('checked');
    var isUnsetForbidden = (is_disabled_flg === '1');

    // 「未設定への変更禁止」かつ「未設定を選択中」なら【エラーがある(true)】
    return isUnsetForbidden && isUnsetSelected;
},

hasErrorLockedOptions: function () {
    // ロックされた選択肢が変更されていたら【エラーがある(true)】
    // (変更がなければ false を返す)
}

このように定義しておくと、メインの判定部分から !(びっくりマーク)が完全に消滅します。

// どれか一つでも「エラーがある(true)」なら実行
var isPlanError     = _self.hasErrorPlanChange();
var isOptionError   = _self.hasErrorLockedOptions();
var isCategoryError = _self.hasChangedCategoryValues();

if (isPlanError || isOptionError || isCategoryError) {
    alert("変更できない値が含まれています");
    return false; // 処理を中断(早期リターン)
}

「エラーがあったらアラートを出す」 という、人間の直感的な思考とコードのロジックが完全に一致するため、チーム開発でも格段に読みやすくなります。


2. 連想配列・オブジェクトの空チェックは $.isEmptyObject() が最強

JSONをパースしたオブジェクトや連想配列 {} の中身が空かどうかを判定するとき、if (obj) だけでチェックしようとするのはNGです。なぜなら、JavaScriptにおいて {}(空のオブジェクト)は true と判定されてしまうから です。

早期リターン(ガード句)を使ってスッキリ書くなら、jQueryの便利メソッドを使いましょう。

function processSettings(settingsObj) {
    // settingsObj が null/undefined、または空オブジェクト「{}」なら即リターン
    if (!settingsObj || $.isEmptyObject(settingsObj)) {
        return false; 
    }

    // ここから下は「確実に中身(キーや値)がある」状態
    // ネストを深くせずにメイン処理が書ける
    console.log("設定が存在するので処理を続行します");
}

💡 覚えておきたい挙動

$.isEmptyObject() は、nullundefined が渡されてもエラーにならず、安全に true(空である)を返してくれます。レガシー環境(古いjQuery環境など)でもブラウザの挙動に左右されず安全に動くため、実務で非常に重宝します。


3. 実務の罠:.data().attr() の決定的な違い

HTMLの data- 属性から値を取得するとき、なんとなく .data() を使っていませんか?
ここが実務で最もバグを生み出しやすいポイントです。

🚨 動かないコードの例

以下のようなHTMLがあるとします。

<div class="target-block" data-item-type="0"></div>

これをJS側で受け取って、サーバーから受け取ったJSONデータのキーと照合しようとします。

const type = $_targetElm.data('item-type'); // 数値の 0 が取れる

// JSONデータのキーは「文字列」
const configData = { "0": ["Premium"] }; 

// 型まで厳密に比較(===)するロジックの中で...
if (type === "0") { // 0 === "0" は false になる!!
    // ここを通らない!
}

🧐 なぜ起きた?

原因は、jQueryの 「自動的な型変換」 です。

メソッド 取得先 戻り値の型 data-item-type="0" のとき
.attr('data-item-type') HTMLの属性を直接見る 常に 文字列 (String) "0"(文字列)
.data('item-type') jQueryのメモリ内キャッシュ 自動で 最適な型に変換 0(数値)

.data() は「あ、これ数字の0だな」「true って書いてあるから真偽値(Boolean)だな」と気を利かせて勝手に型を変えてしまいます。そのため、JSONのキー(常に文字列)と比較したり、$.inArray() で厳密に配列内を検索したりするときに、「値は合っているのに型が違って不一致になる」 という怪奇現象が起きます。

💡 解決策

画面のHTMLに書いてある文字をそのまま、手堅く文字列として扱いたいバリデーションなどの処理では、最初から .attr() を使うのが一番安全です。

// HTMLに書いてある文字をそのまま文字列 "0" として取得する
const type = $_targetElm.attr('data-item-type') || '';


まとめ

  1. if 文の中に !(否定)が増えてきたらリファクタリングのサイン。
    「〜に成功したか?」ではなく「〜のエラーがあるか?」に思考を切り替えて関数を設計してみよう。
  2. オブジェクトの空判定は $.isEmptyObject() を使う。
    {}if 文をスルーしてしまう罠を回避しよう。
  3. data- 属性を扱うときは「型」を意識する。
    jQueryにお節介な型変換をされたくない時は .attr('data-...') を使おう。

ちょっとした意識の差で、デバッグの時間もコードの綺麗さも劇的に変わります。ぜひ実務のコードで試してみてください!

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?