はじめに
JavaScriptは演算子をうまく使うことで、値がnullのときの挙動を決めたり、デフォルト値を設定したりすることができます。
本記事では5つのTipsを紹介します。
前提知識
JavaScriptには型が存在していますが、明示的に型を宣言する必要はありません。
これは、実行時にJavaScriptが自動で型を評価してくれるためです。
また、型の変換も自動で行ってくれます。
(この仕様がバグの温床となることもあるのですが…)
中でも、真偽値に変換したときtrue
となる値をtruthyな値、false
となる値をfalsyな値と呼びます。
以下はその一覧です。
truthy | falsy |
---|---|
falsy以外のすべての値 | null、undefined、NaN、0、""(空文字) |
厳密には上記でfalsyをすべて網羅しているわけではありません。
細かく確認する場合は以下を確認してください。
https://developer.mozilla.org/ja/docs/Glossary/Falsy
truthy、falsyの概念を抑えておいてください。
"||"を使ったデフォルト値の設定
基本の説明
すでにご存知の方が多いかと思いますが、基本から確認します。
||
は論理和と呼ばれる演算子です。
一般的には以下のように使います。
if (score > 100 || score < 0) {
// なにかの処理
}
設定した条件のうち、いずれかが真ならtrue
、すべて偽ならfalse
となる演算子であると認識しているかと思います。
しかし、その実態を正確に理解するのであれば
- 値がtruthyならばその値を返す
- falsyなら次の値を評価する
という挙動になっています。
どういうことか順を追って確認します。
let score = 110;
if (score > 100 || score < 0) {
// なにかの処理
}
score = -1;
if (score > 100 || score < 0) {
// なにかの処理
}
score = 50;
if (score > 100 || score < 0) {
// なにかの処理
}
scoreが110のとき
score > 100
は真になるので、score > 100
の評価結果であるtrue
が返ってきます。
よって、if()
にはtrue
が設定されます。
scoreが-1のとき
score > 100
は偽になるので、score < 0
を評価します。
結果は真であるので、if()
にはtrue
が設定されます。
scoreが50のとき
score > 100
は偽になるので、score < 0
を評価します。
こちらも偽になりますが、ほかに評価対象がないのでif()
にはfalse
が設定されます。
このように、一つずつ順番に評価して、truthyな値があればそれを返す。
なければ最後の値を返す、という挙動になっているのです。
デフォルト値の設定
前置きが長くなりましたが、この挙動を応用すると値が未設定のときにデフォルト値を設定することができます。
userName
という変数に対して、user
オブジェクトのname
プロパティを設定したいとします。
またname
プロパティが未設定の場合、デフォルト値としてTaro
を設定したいです。
if文を使わずに、以下のように書くことができます。
const userName = user.name || "Taro";
一見すると条件式でもないのに||
を使っているのが奇妙に思えますが、先ほど確認した論理和の挙動をなぞれば簡単に理解できます。
user.nameがtruthy(設定済)の場合
user.name
が設定されている場合、true
であるとみなされます。
よって、userName
にはuser.name
が設定されます。
ここでのポイントはあくまでもuser.name
の値がそのまま設定されるということです。
(真偽値に変換後の値が設定されるわけではない)
user.nameがfalsy(未設定)の場合
user.name
がnull
やundefined
など未設定の場合、false
とみなされます。
よって、"Taro"
の評価に移ります。
"Taro"
はtruthyなのでuserName
には"Taro"
が設定されます。
このように、falsyな値の場合には次の値に移ることを利用して、デフォルト値の設定をすることができました。
""(空文字)や、数値の0はfalsyであるため想定外の挙動になる可能性があり、考慮が必要です。
"&&"を使った条件付き処理実行
基本の説明
こちらも基本から確認します。
&&
は論理積と呼ばれる演算子です。
一般的には以下のように使います。
if (isAdmin && isAuthenticated ) {
// なにかの処理
}
設定した条件がすべて真ならtrue
、一つでも偽ならfalse
となる演算子であると認識しているかと思います。
しかし、その実態を正確に理解するのであれば
- 値がfalsyならばその値を返す
- 値がtruthyなら次の値を評価する
という挙動になっており、||
とは逆になっています。
つまり、一つずつ値を順番に評価して、falsyな値があればそれを返す。
なければ最後の値を返します。
条件付き処理の実行
ある条件を満たす場合にのみ、実行したい処理があるとします。
管理者の場合に、機能を有効化する処理を実行する場合を考えてみます。
if文を使わずに、以下のように書くことができます。
isAdmin && enableFunction();
isAdminがtruthy(管理者)の場合
isAdmin
はtrue
なので、次の値の評価に移ります。
よって、enableFunction
が実行されます。
isAdminがfalsy(管理者ではない)の場合
isAdmin
はfalse
なので、false
がそのまま返ります。
評価はそこで終わるので、enableFunction
の実行には到達しません。
このようにfalsyな値の場合にはそこで評価が止まることを利用して、条件を満たす場合にのみ実行される処理を定義することができました。
"!!"を使った真偽値への変換
基本の説明
!
は論理否定と呼ばれる演算子です。
一般的には以下のように使います。
if (!isNaN(num)) {
// 何らかの処理
}
真偽値を反転させます。true
ならfalse
に、false
ならtrue
にします。
真偽値への変換
!
は真偽値でない値にも使用できます。
真偽値以外の場合にはtruthy
ならfalse
に、falsy
ならtrue
にします。
そして、!!
は否定の否定、二重否定と呼ばれます。
つまり反対の反対なので、truthy
ならtrue
に、falsy
ならfalse
にします。
明示的に値を真偽値に変換したい場合に使用することができます。
const userName = "Taro";
console.log(`${userName}:${!!userName}`); // Taro:true
const num = 100;
console.log(`${num}:${!!num}`); // 100:true
const hoge = undefined;
console.log(`${hoge}:${!!hoge}`); // undefined:false
ただ、これはBoolean
関数を使っても同じことができるので、あまり使う機会はないかもしれません。
オプショナルチェーン(?.)の使い方
今まで紹介した3つのtipsは従来のJavaScriptにもともとあった演算子を応用した使い方でした。
ここから紹介する2つのtipsは、比較的新しい書き方になります。
ECMAScript(JavaScriptの仕様のようなもの)の2020バージョン(ES2020)から使える記法です。
概要
オプショナルチェーンは、オブジェクトのプロパティがnull
またはundefined
のときに、エラーにせずundefined
を返します。
オプショナルチェーンを使わない場合
users
オブジェクトのfetchUserInfo
メソッドで、指定したname
の情報から住所を取得したいとします。
const userAddress = users.fetchUserInfo(name).address;
もし、fetchUserInfo
の結果がnull
またはundefined
の場合、エラーが発生します。
null
またはundefined
の値に対してaddress
プロパティを取得しようとするためです。
値を取得できない可能性がある場合、if文を書いてチェックをする必要があります。
オプショナルチェーンを使う場合
オプショナルチェーンを使うと、値のチェックが不要になります。
const userAddress = users.fetchUserInfo(name)?.address;
?.
を使っています。
fetchUserInfo
の結果がnull
またはundefined
の場合、address
の取得をせず、undefined
を返却します。
これにより、エラーの発生を防ぐことができます。
Null合体演算子(??)の使い方
こちらも新しい書き方です。
概要
||
と似た挙動をします。
- 値がNull値(
null
、undefined
)なら次の値を評価する - 値がNull値でないならばその値を返す
という挙動になります。
||
はtruthy、falsyでの判断だったため、""(空文字)や数値の0の場合には考慮が必要でした。
しかし、??
はNull値の場合にのみ次の値に移るため、より正確に評価することができます。
Null合体演算子を使わない場合
デフォルト値設定のため、||
を使うとすると、意図しない挙動になる場合があります。
// user.nameが""(空文字)の場合でも、デフォルト値が設定される
const userName = user.name || "Taro";
// user.hpが0の場合でも、デフォルト値が設定される
const hitPoint = user.hp || 50;
""(空文字)をそのまま設定したい、0をそのまま設定したい、という場合には||
は使えません。
Null合体演算子を使う場合
// user.nameが""(空文字)の場合、デフォルト値が設定される
const userName = user.name ?? "Taro";
// user.hpが0の場合、デフォルト値が設定される
const hitPoint = user.hp ?? 50;
??
を使うと、null
またはundefined
の時のみデフォルト値が設定されるようになるため、""(空文字)や0をそのまま設定することが可能です。
ケースによって使い分けが必要ですが、基本的には??
を使うのがよいでしょう。
まとめ
演算子を利用して、便利に処理を書く方法を確認してきました。
うまく使えば、コード量を少なく、簡潔に書くことができます。
しかし、複雑な処理で多用すると、かえって可読性が下がる場合もあるので、状況に応じて使い分けることが重要です。