【JavaScript】 Nullishな値に関する演算 Null合体演算子とオプショナルチェーン演算子
更新日:2023/02/21
nullishな値とは、nullまたはundefinedを指します。
この値に関する演算子に、Null合体演算子とオプショナルチェーン演算子があります。
ここでは、この二つの機能について簡単に解説していきます。
Nullish Coalescing Operator(Null合体演算子)
Coalescing Operatorは日本語にすると、合体演算子です。
Nullish Coalescing Operatorだと、Null合体演算子です。
Null合体演算子は、OR演算子( || )やAND演算子( && )に似ています。
|| と && は左辺と右辺が真または偽とみなされる値かどうかをチェックします。
偽とみなされる値:false,null,undefined,0,空文字(""),Nan
左辺 || 右辺: 左辺が真なら左辺の値を返す。左辺が偽なら右辺の値を返す。
左辺 && 右辺: 左辺が偽なら左辺の値を返す。左辺が真なら右辺の真偽値を返す。
結果が真偽値ではなくて、対象の値であることに注意。
それに対し、Null合体演算子??はnullまたはundefinedかどうかをチェックします。
Nullish Coalescing Operatorの構文
左辺値 ?? 右辺値
左辺がnullまたはundefinedでないなら左辺の値。
nullまたはundefinedなら、右辺の値を演算結果として返します。
同じ結果を得るコードを3項演算子で記述すると次のようになります。
( 左辺値 !== null && 左辺値 !== undefined ) ? 左辺値 : 右辺値
Null合体演算子は上記のような演算を置き換えるものと考えていいかもしれません。
なおOR演算子やAND演算子を同時に使用する場合、( )を使って優先順位を明確にしないとエラーになります。
NG
変数1 || 変数2 ?? 変数3
OK
(変数1 || 変数2 ) ?? 変数3
またOR演算子やAND演算子と同様に短絡評価がおこなわれます。
左辺値が適用された場合、右辺値は演算されません。
例えば、次のようなコードです。
aがNullishなら、3で初期化
a ?? ( a = 3 );
aがnullまたはundefinedなら、aに値をセットしています。
実際には、 a = a ?? 3 と記述する方がわかりやすいですが、いい例が思いつきませんでした。
もう一つ挙げてみます。
func関数からNullish以外が返されたら停止
const func = p => p;
func( null ) ?? func( undefined ) ?? func( 0 ) ?? func( null ); // 4つめのfuncは実行されない
nullなら処理終了するパターンが多いと思いますが、上の例はnull(undefinedも含む)なら処理続行です。
func()は受け取った値を返しているだけですが、何らかの処理した結果を返していると想定してください。
本来ならif文を多用するところを、簡潔に記述できていますね。
ただし、コードの意図が分かりにくくなることが多いので、そうならないための何らかの配慮が必要です。
const isNull = e => e === null || e === undefined;
const func = p => p;
isNull(func(0)) || isNull(func(1)) || isNull(func(null)) || func(null); // 4つめのfuncは実行されない
Optional Chaining(オプショナルチェーン演算子)
Optional Chainingは、オブジェクトのプロパティアクセスに関する機能です。
Optional Chainingの使用例
const obj = {
func1: () => "hello",
func2: null,
func4: "abc"
};
console.log(obj.func1?.());// "hello"
console.log(obj?.func2?.());// undefined
console.log(obj?.func3?.());// undefined
console.log(obj?.func4?.());// TypeError: obj.func4 is not a function
オプショナルチェーン演算子(?.)は、演算子の前のプロパティが存在しないまたは、プロパティの値がnullまたはundefinedの時に undefined を返して、以後の評価を停止します。
オプショナルチェーン演算子を使ったパターンをいくつか挙げてみます。
Optional Chainingの使用パターン
1 : オブジェクト.プロパティ名?.プロパティ名
2 : オブジェクト[プロパティ名]?.プロパティ名
3 : オブジェクト.プロパティ?.[プロパティ名]
4 : オブジェクト[プロパティ名]?.[プロパティ名]
5 : オブジェクト.プロパティ?.( 引数 )
6 : オブジェクト[プロパティ名]?.( 引数 )
7 : オブジェクト.プロパティ( 引数 )?.プロパティ( 引数 )
8 : オブジェクト.プロパティ( 引数 )?.[プロパティ名]( 引数 )
?.[プロパティ名]と?.( 引数 )は、プロパティアクセスの . に [] または () が続いているように見えるので不思議な印象を受けますね。
実際には、?.で一つの演算です。
そう思ってみると、違和感が消えると思います。
オプショナルチェーン演算子は、エラーを抑制する演算子ではないという点に注意が必要です。
演算子の前のプロパティがnullishな値でない時は、そのまま次の評価が行われます。
例えばプロパティ値が文字列のとき、 () を適用するとエラーになります。
const obj = {
a : ()=>"hello",
b : "abc"
}
console.log( obj.a?.() );
console.log( obj.b?.() );
よく考えると当たり前の現象ですが、問題なく動くような錯覚に陥ることがあります。
罠にはまらないようにしましょう。
Optional Chainingを、3項演算子で記述すると次のようになります。
Optional Chainingの代替
(変数.プロパティ !== null && 変数.プロパティ !== undefined) ? 変数.プロパティ : undefined;
undefined評価時に停止する動作は、この3項演算子で表現できないですね…
厳密にはできますが、あまり意味が無いのでこれ以上は考えません。
オプショナルチェーン演算子は、次のようなプロトタイプチェーンで、途中で処理を中断させたい時などに効果を発揮します。
const obj = {
func : function(e){
this.count++;
return (e===null || e===undefined) ? undefined : this;
},
count : 0
}
obj.func(1)?.func(0)?.func(null)?.func("abc");
console.log( obj.count ); // 3
ここまでオブジェクトで使用するような表現をしていますが、変数でも使用できます。
const a = ()=>"hello";
console.log( a?.() ); // hello
const b = null;
console.log( b?.() ); // undefined
console.log( c?.() ); // ReferenceError: c is not defined
未定義の変数はエラーになりました。
これは参照した時点でエラーになり、オプショナルチェーン演算子の評価まで到達しないからです。
更新日:2023/02/21
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。