「null 合体代入」とは何をしてくれる構文か
「null 合体代入」は、
「その変数が null または undefined のときだけ、デフォルト値を代入する」
ということを一発で書ける構文です。
JavaScript では、これを ??= という演算子で書きます。
value ??= defaultValue;
JavaScript意味としては、こうです。
if (value === null || value === undefined) {
value = defaultValue;
}
JavaScriptこれを一行で、しかも意図がはっきりした形で書けるのが「null 合体代入」です。
まずは基本:null 合体演算子 ?? との関係
?? と ??= の違いを押さえる
?? は「式」として使う演算子です。
const pageSize = input.pageSize ?? 20;
JavaScriptこれは「input.pageSize が null / undefined なら 20、それ以外ならそのまま」という意味です。
一方、??= は「代入演算子」です。
pageSize ??= 20;
JavaScriptこれは「pageSize が null / undefined のときだけ 20 を代入する」という意味です。
つまり、
x = x ?? defaultValue;
JavaScriptを短く書いたのが
x ??= defaultValue;
JavaScriptだと思ってもらえば OK です。
null 合体代入の基本的な挙動
どんなときに代入されるのか
いくつかパターンを見てみましょう。
let value;
// 1. undefined のとき
value = undefined;
value ??= 10;
console.log(value); // 10
// 2. null のとき
value = null;
value ??= 10;
console.log(value); // 10
// 3. 0 のとき
value = 0;
value ??= 10;
console.log(value); // 0(そのまま)
// 4. 空文字のとき
value = "";
value ??= "default";
console.log(value); // ""(そのまま)
// 5. false のとき
value = false;
value ??= true;
console.log(value); // false(そのまま)
JavaScriptここで一番大事なポイントは、
「0 や "" や false は“ちゃんとした値”として扱われ、上書きされない」ということです。
||=(論理和代入)と混同すると危険なので、違いを意識しておきましょう。
なぜ業務で「null 合体代入」が効いてくるのか
業務コードでは、「設定値」「オプション」「外部入力」がとにかく多いです。
例えば、こんな状況を考えてみます。
let options = {
pageSize: undefined,
theme: "dark",
};
JavaScriptここで、「pageSize が指定されていなければ 20 を入れたい」というとき、
null 合体代入を使うとこう書けます。
options.pageSize ??= 20;
console.log(options);
// { pageSize: 20, theme: "dark" }
JavaScriptもし pageSize に 0 が入っていたら、それは「意図的に 0 を指定した」とみなして、そのまま残ります。
options.pageSize = 0;
options.pageSize ??= 20;
console.log(options.pageSize); // 0 のまま
JavaScript「null / undefined のときだけデフォルトを入れる」
という業務でよくある要件を、短く・安全に書けるのが null 合体代入です。
よくある「ダメな書き方」との比較
||= を使ってしまうと何が起きるか
似た構文に ||=(論理和代入)があります。
value ||= 10;
JavaScriptこれは「value が falsy(0, “”, false, null, undefined など)のときに 10 を代入する」という意味です。
業務でやりがちなのが、これを「デフォルト代入」として使ってしまうことです。
let pageSize = 0;
pageSize ||= 20;
console.log(pageSize); // 20(0 が消える)
JavaScript「0 も有効な値」として扱いたい場面では、これはバグになります。
同じことを null 合体代入で書くとこうなります。
let pageSize = 0;
pageSize ??= 20;
console.log(pageSize); // 0(意図通り)
JavaScriptここが null 合体代入を“安全処理”として使う最大のポイントです。
「0 や空文字を潰さない」「本当に“値がない”ときだけデフォルトを入れる」ことができます。
ユーティリティとしての null 合体代入の使い方
設定オブジェクトの初期化
設定オブジェクトに対して、「足りないところだけ埋める」処理はよく出てきます。
function initOptions(options) {
options.pageSize ??= 20;
options.theme ??= "light";
options.lang ??= "ja";
return options;
}
JavaScript使い方はこうです。
const userOptions = { theme: "dark" };
const finalOptions = initOptions(userOptions);
console.log(finalOptions);
// { theme: "dark", pageSize: 20, lang: "ja" }
JavaScriptここでのポイントは、
「ユーザーが指定していない項目だけデフォルトを入れる」
「null / undefined のときだけ埋める」
というルールが、??= でとても素直に表現できていることです。
「undefined 防止代入」との関係
以前話した「undefined 防止代入」と、null 合体代入はかなり近い発想です。
undefined 防止代入
「undefined のときだけ上書きしない/上書きする」
null 合体代入
「null / undefined のときだけデフォルトを代入する」
どちらも、「よく分からない値で、ちゃんとした値を壊したくない」という目的を持っています。
違いは、「null をどう扱うか」です。
undefined だけ特別扱いしたいなら、自前の条件やユーティリティ関数を使うnull も「値がない」とみなしたいなら、??=` を使う
という整理をしておくと、設計がぶれません。
実務での具体的な利用イメージ
API レスポンスの補完
API からのレスポンスに「オプション項目」がある場合、
「なければデフォルトを入れてから使う」というのはよくあるパターンです。
function normalizeUser(raw) {
raw.name ??= "名無し";
raw.role ??= "user";
raw.active ??= true;
return raw;
}
JavaScriptこれで、「name が null / undefined のユーザーでも、アプリ内部では必ず文字列として扱える」状態になります。
ローカルストレージからの復元
ローカルストレージから設定を復元するときも、null 合体代入は相性がいいです。
function loadSettings() {
const json = localStorage.getItem("settings");
const settings = json ? JSON.parse(json) : {};
settings.theme ??= "light";
settings.lang ??= "ja";
return settings;
}
JavaScript「保存されていない項目だけデフォルトを入れる」という処理が、かなり読みやすく書けます。
小さな練習で感覚をつかむ
次のような値を用意して、自分で ??= と ||= の挙動を比べてみてください。
let v;
// それぞれについて v ??= 100 と v ||= 100 を試す
v = undefined;
v = null;
v = 0;
v = "";
v = false;
v = 123;
JavaScript「どのときに上書きされるか」「どのときに元の値が残るか」を自分の目で確認すると、
「null 合体代入は“本当に値がないときだけ埋める”ためのもの」
という感覚がしっかり入ってきます。
そこまで理解できたら、あとはあなたのプロジェクトの中で、
「ここ、null / undefined のときだけデフォルトを入れたいんだよな」
という場所に、少しずつ ??= を差し込んでいけば、
設定やオプションまわりのバグがかなり減っていきます。
