目次
Null合体演算子(Nullish coalescing operator)について
Null合体演算子(??
)とはvalue ?? defaultValue
のように記述し、左辺(value
)がnullishな値(null
もしくはundefined
)の時は右辺(defaultValue
)、そうでない時は左辺value
を返す演算子です。
value ?? defaultValue
とvalue != null ? value : defaultValue
は同じ結果になります。
なお、 Null合体代入演算子(Logical nullish assignment operator)というNull合体演算子と名前が似ている演算子もあります。
Null合体代入演算子の詳細解説はNull合体代入演算子(Logical nullish assignment operator)の基本で紹介しています。
Null合体演算子を利用したリファクタリング例
Null合体演算子を利用したリファクタリング例を紹介します。
今回利用するサンプルコード
引数がなければHello
、あれば引数の文字列を返すcreateMessage
というメソッドがあったとします。
Null合体演算子を利用せずに実装すると以下のようになります。
const createMessage = (text) => {
if (text != null) {
return text
} else {
return "Hello"
}
}
const defaultMessage = createMessage()
console.log(defaultMessage) // Hello
const morningMessage = createMessage("Good morning")
console.log(morningMessage) // Good morning
三項演算子を使って以下のようにも表現できます。
const createMessage = (text) => {
const message = text != null ? text : "Hello"
return message
}
const defaultMessage = createMessage()
console.log(defaultMessage) // Hello
const morningMessage = createMessage("Good morning")
console.log(morningMessage) // Good morning
Null合体演算子を利用して書きなおした例
Null合体演算子を利用すると以下のように書き換えられます。
const createMessage = (text) => text ?? "Hello"
const defaultMessage = createMessage()
console.log(defaultMessage) // Hello
const morningMessage = createMessage("Good morning")
console.log(morningMessage) // Good morning
Null合体演算子とOR演算子の違いについて
Null合体演算子と似た短絡評価(ショートサーキット)を行う演算子にOR演算子(||
)があります。
短絡評価とは『左辺を評価した段階で式の結果が決まらない場合のみ右辺を評価する(式の結果が決まった時点で後続の評価をしない)』という評価方法のことをいいます。
OR演算子はvalue || defaultValue
と記述すると、左辺(value
)がfalsyな値(偽値、falseyな値)なら右辺(defaultValue
)、そうでなければ左辺(value
)を返す演算子です。
falsyな値とはfalse
と評価される値のことを指します。
value || defaultValue
とvalue ? value : defaultValue
は同じ結果になります。
JavaScriptにおけるfalsyな値は以下の8つです。1
- false
- 0
- -0
- “”
- null
- undefined
- NaN
value || defaultValue
では上記8種類全てがdefaultValue
になります。
null || 'default' // 'default'
undefined || 'default' // 'default'
false || 'default' // 'default'
0 || 'default' // 'default'
-0 || 'default' // 'default'
0n || 'default' // 'default'
"" || 'default' // 'default'
NaN || 'default' // 'default'
一方、value ?? defaultValue
ではundefined
とnull
のみがdefaultValue
となります。
null ?? 'default' // 'default'
undefined ?? 'default' // 'default'
false ?? 'default' // false
0 ?? 'default' // 0
-0 ?? 'default' // -0
0n ?? 'default' // 0n
"" ?? 'default' // ""
NaN ?? 'default' // NaN
オプショナルチェーン演算子(Optional chaining operator)
オプショナルチェーン演算子(?.
)とはobj?.value
のように記述し、obj
がnullishな値の時はundefined
、そうでない場合はvalue
を返す演算子です。
obj?.value
とobj != null ? obj.value : undefined
は同じ結果になります。
オプショナルチェーン演算子を利用するとnullishなオブジェクトのプロパティにアクセスした場合もエラーが発生しません。
let user
console.log(user.name) // TypeError: Cannot read property 'name' of undefined
console.log(user?.name) // undefined
nullishな可能性のあるオブジェクトのプロパティへアクセスする場合はオプショナルチェーン演算子を利用するとよいです。
オプショナルチェーン演算子とNull合体演算子を組み合わせた例
以下はname
プロパティが存在しなければAnonymous
、存在していればname
を返す例です。
オプショナルチェーン演算子とNull合体演算子を組み合わせることで『プロパティが存在しなかった場合のプロパティのデフォルト値』が設定できます。
let anonymousUser
const anonymousUserName = anonymousUser?.name ?? 'Anonymous'
console.log(anonymousUser) // undefined
console.log(anonymousUserName) // Anonymous
const user = { name: "Bob" }
const userName = user?.name ?? 'Anonymous'
console.log(user) // { name: 'Bob' }
console.log(userName) // Bob
オプショナルチェーン演算子とOR演算子を組み合わせると意図しない挙動になる可能性がある
先ほどのコードはNull合体演算子をOR演算子に書き換えても意図した挙動になります。
let anonymousUser
const anonymousUserName = anonymousUser?.name || 'Anonymous'
console.log(anonymousUser) // undefined
console.log(anonymousUserName) // Anonymous
const user = { name: "Bob" }
const userName = user?.name || 'Anonymous'
console.log(user) // { name: 'Bob' }
console.log(userName) // Bob
Null合体演算子とOR演算子は書き換え可能に見えますが、プロパティにfalsyな値がセットされる場合は注意が必要です。
以下はpoint
プロパティがなければ100、あればpoint
の値を返す例です。
0はJavaScriptにおいてfalsyな値であるため、OR演算子で実装するとpoint
に0をセットしても100が返されてしまいます。
let defaultBonus
const defaultBonusPoint = defaultBonus?.point || 100
console.log(defaultBonusPoint) // 100
const superBonus = { point: 5000 }
const superBonusPoint = superBonus?.point || 100
console.log(superBonusPoint) // 5000
const zeroBonus = { point: 0 }
const zeroBonusPoint = zeroBonus?.point || 100
console.log(zeroBonusPoint) // 100 ← 0はfalsyな値なのでOR演算子の場合は右辺がセットされる。意図した挙動にならない可能性があるので注意。
Null合体演算子であれば上記のような問題は発生しません。
let defaultBonus
const defaultBonusPoint = defaultBonus?.point ?? 100
console.log(defaultBonusPoint) // 100
const superBonus = { point: 5000 }
const superBonusPoint = superBonus?.point ?? 100
console.log(superBonusPoint) // 5000
const zeroBonus = { point: 0 }
const zeroBonusPoint = zeroBonus?.point ?? 100
console.log(zeroBonusPoint) // 0
オプショナルチェーンはプロパティの値もしくはnullishな値しか返さないので、Null合体演算子と組み合わせるのが無難です。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!