if文で&&を使った際の挙動で思っていたのと違うということがあったので、調べたことをメモ。
サンプルコード
まずはif文で試す前に、オブジェクト内の値を取得するサンプルです。
const data = { name: 'suzuki', age: 18 }; console.log(data.size); // undefined console.log(data.size.height); // Uncaught TypeError: Cannot read properties of undefined (reading 'height')
6行目のように存在しないkey値を取得しようとするとundefinedになり、7行目のようにundefinedに対して参照するとエラーになります。
undefinedの参照でエラーになるデモページ
上記でエラーになった参照をif文で使うと、同じくエラーになります。
const data = { name: 'suzuki', age: 18 }; if(data.size.height) { // Uncaught TypeError: Cannot read properties of undefined (reading 'height') console.log('if'); } else { console.log('else'); }
次の例が本題ですが、if文で&&を使って以下のようにした場合も同様にエラーになるかと思っていたのですが、この場合はエラーにならずelseの方の分岐に入ります。
const data = { name: 'suzuki', age: 18 }; if(data.size && data.size.height) { console.log('if'); } else { console.log('else'); // else }
「expr1 && expr2」で「expr1がtrue」かつ「expr2がtrue」の場合という条件になるになるという認識でいたのですが、以下に記載の通り、最初のexpr1がfalseだった時点でfalseを返す(以降の条件は確認しない)という処理になっているようです。
短絡評価
論理積の式は短絡演算子です。
各オペランドが論理値に変換されるとき、ある変換結果がfalse
であった場合、論理積演算子は停止してその偽値のオペランドの元の値を返します。残りのオペランドは評価されません。以下の擬似コードを考えてみてください。
(偽値の式) && expr
expr
の部分は評価されません。最初のオペランドである(偽値の式)
が偽値と評価されるからです。
expr
が関数であった場合、その関数は呼び出されません。引用 – 論理積 (&&) – JavaScript | MDN
|| の場合も試してみます。
const data = { name: 'suzuki', age: 18 }; if(data.size || data.size.height) { // Uncaught TypeError: Cannot read properties of undefined (reading 'height') console.log('if'); } else { console.log('else'); }
&& を || に変更しましたが、この場合はエラーになります。
if文でエラーになるデモページ2
次に最初の条件がtrueになる例で試してみます。
const data = { name: 'suzuki', age: 18 }; if(data.name || data.size.height) { console.log('if'); // if } else { console.log('else'); }
この場合はエラーになりませんでした。
if文でエラーにならないデモページ2
|| の場合、「expr1 || expr2」で「expr1がtrue」または「expr2がtrue」の場合という条件になりますが、この時 最初のexpr1がtrueの時点でtrueを返す(以降の条件は確認しない)という処理になっているようです。
短絡評価
論理和の式は左から右へと評価され、下記の規則を使用して「短絡」評価が可能なように評価されます。
(真値の式) || expr
は短絡評価で真値の式に評価されます。短絡とは、上記の
expr
の部分が評価されず、したがって、これを行うことの副作用が効果を及ぼさないことを意味します(例えば、expr
が関数呼び出しであった場合、この場では呼び出されません)。これは、最初のオペランドが評価された時点で、すでに演算子の値が決定しているためです。例を示します。引用 – 論理和 (||) – JavaScript | MDN
コメントが承認されるまで時間がかかります。