[JavaScript講座] モダンな演算子と構文

当ページのリンクには広告が含まれています。
目次

Null合体演算子 ??

|| との違い

前の章で || を「デフォルト値」に使えると説明しました。

const input = "";              // ユーザー入力(今は空文字)
const name = input || "名無し";

console.log(name); // "名無し"

でも、「空文字 "" 自体を有効な値として扱いたい」場面では困ります。

ここで登場するのが Null合体演算子 ?? です。

const input = "";
const name = input ?? "名無し";

console.log(name); // ""(空文字がそのまま使われる)

挙動の違い:

  • A || B
    → A が Falsy なら B、そうでなければ A
  • A ?? B
    → A が null または undefined なら B、そうでなければ A

つまり、?? は「null / undefined のときだけデフォルト値」という意味になります。

具体的な比較

console.log(0 || 42);        // 42(0 は Falsy)
console.log(0 ?? 42);        // 0  (0 は null/undefined ではない)

console.log("" || "default");  // "default"(空文字は Falsy)
console.log("" ?? "default");  // ""(空文字は null/undefined ではない)

console.log(null || "default");    // "default"
console.log(null ?? "default");    // "default"

console.log(undefined || "default"); // "default"
console.log(undefined ?? "default"); // "default"

実務的な指針:

  • 「未設定(null/undefined)のときだけ デフォルトを使いたい」 → ??
  • 「0 や空文字も“ないもの”として扱いたい」 → ||

オプショナルチェイニング ?.

undefined / null によるエラー

よくあるエラー:

const user = null;

// console.log(user.name); // TypeError: Cannot read properties of null

usernullundefined のときにプロパティアクセスするとエラーになります。

それを避けるために、今まではこんな書き方をしていました。

const userName = user && user.name ? user.name : "名無し";

?. で安全にアクセス

オプショナルチェイニング ?. を使うと:

const user = null;

const name = user?.name ?? "名無し";

console.log(name); // "名無し"

user?.name の挙動:

  • usernull or undefined のとき
    user?.name は エラーではなく undefined を返す
  • それ以外(オブジェクトが入っている)とき
    → 通常通り user.name を評価

組み合わせると:

const name = user?.name ?? "名無し";

意味:

user があって name が取れればその値、取れなければ '名無し'

ネストにも使える

const user = {
  profile: {
    name: "Taro",
  },
};

console.log(user.profile.name);       // "Taro"
console.log(user.profile?.name);      // "Taro"
console.log(user.address?.city);      // undefined(エラーにならない)
console.log(user.address?.city ?? "不明"); // "不明"

「深くネストしたオブジェクトの一部が無いかもしれない」
という場面で、?. は非常に便利です。

論理代入演算子 &&=, ||=, ??=

「既存の値」に基づいて、「条件付きで代入する」ためのショートカットです。

||=:Falsy のときだけ代入

let name = "";       // まだ未設定という扱いにしたい
name ||= "名無し";

console.log(name);   // "名無し"

これは、次と同じ意味です:

let name = "";
if (!name) {
  name = "名無し";
}
  • 左辺が Falsy なら右辺を代入
  • それ以外は何もしない

&&=:Truthy のときだけ代入

let isEnabled = true;
let flag = true;

flag &&= isEnabled;

console.log(flag); // true(両方 true)

flag = false;
flag &&= isEnabled;

console.log(flag); // false(最初が Falsy なので代入されない)

これは、次と同じ意味です:

if (flag) {
  flag = isEnabled;
}

??=:null/undefined のときだけ代入

?? と同じく、「null/undefined のときだけ」というバージョンです。

let title = null;
title ??= "デフォルトタイトル";

console.log(title); // "デフォルトタイトル"

let count = 0;
count ??= 10;

console.log(count); // 0(0はnull/undefinedではないのでそのまま)

これは、次と同じ意味です:

if (title === null || title === undefined) {
  title = "デフォルトタイトル";
}

実務的には:

  • 「未設定(null/undefined)のときだけ初期値を入れたい」 → ??=
  • 「とにかく Falsy のときだけ初期値」 → ||=
    (ただし 0 や “” も上書きされる)

分割代入(destructuring)

配列の分割代入

従来:

const arr = [1, 2, 3];

const a = arr[0];
const b = arr[1];
const c = arr[2];

分割代入:

const arr = [1, 2, 3];

const [a, b, c] = arr;

console.log(a, b, c); // 1 2 3

飛ばしたり、デフォルト値もOK:

const arr = [10];

const [x, y = 20] = arr;

console.log(x, y); // 10 20

const [, second] = [100, 200, 300];
console.log(second); // 200

オブジェクトの分割代入

従来:

const user = { name: "Taro", age: 20 };

const name = user.name;
const age = user.age;

分割代入:

const user = { name: "Taro", age: 20 };

const { name, age } = user;

console.log(name, age); // "Taro" 20

別名をつけることもできます:

const user = { name: "Taro", age: 20 };

const { name: userName, age: userAge } = user;

console.log(userName, userAge); // "Taro" 20

デフォルト値:

const user = { name: "Taro" };

const { name, age = 18 } = user;

console.log(name, age); // "Taro" 18

関数引数と組み合わせる

よくあるパターン:

function printUser({ name, age }) {
  console.log(`名前:${name}, 年齢:${age}`);
}

const user = { name: "Hanako", age: 25 };

printUser(user); // 名前:Hanako, 年齢:25

「引数として受け取ったオブジェクトから、一部のプロパティだけ使う」という場面でとても便利です。

スプレッド構文 …(展開)

配列のコピー・結合

const arr1 = [1, 2];
const arr2 = [3, 4];

const arr3 = [...arr1, ...arr2];
console.log(arr3); // [1, 2, 3, 4]

浅いコピーにも使えます:

const original = [1, 2, 3];
const copy = [...original];

copy.push(4);

console.log(original); // [1, 2, 3]
console.log(copy);     // [1, 2, 3, 4]

オブジェクトのコピー・マージ

const base = { a: 1, b: 2 };
const extra = { b: 99, c: 3 };

const merged = { ...base, ...extra };
console.log(merged); // { a:1, b:99, c:3 }
  • 右側にあるプロパティが同じキーを上書きする
  • ... を使うことで「浅いコピー」を簡単に書ける

const と組み合わせると、「参照ではなく中身のコピー」を作れる。

テンプレートリテラル `…`

文字列連結より見やすい書き方

従来:

const name = "Taro";
const score = 90;

const message = "名前:" + name + ", 点数:" + score;
console.log(message);

テンプレートリテラル:

const name = "Taro";
const score = 90;

const message = `名前:${name}, 点数:${score}`;
console.log(message);
  • `...`(バッククォート)で囲む
  • ${ ... } の中に式を書ける(変数だけでなく計算もOK)
const a = 10;
const b = 20;

console.log(`a + b = ${a + b}`); // "a + b = 30"

複数行文字列がそのまま書ける

従来(普通の文字列):

const text = "1行目\n2行目\n3行目";

テンプレートリテラル:

const text = `
1行目
2行目
3行目
`;

console.log(text);
  • 改行やインデントも含めて、そのまま文字列になる
  • ログメッセージや HTML を組み立てるときにかなり便利

<<前へ(演算子の基本と == / ===)

>>次へ(制御構文(if / switch / for / while / break / continue))

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次