写真 旅 ブログ 開発室
HOME開発室[JavaScript] 厳密等価演算子(===)の注意点
キーワード
JavaScript

[JavaScript] 厳密等価演算子(===)の注意点

[JavaScript] 厳密等価演算子(===)の注意点

厳密等価演算子(===)とは

厳密等価演算子(===)は2つの値が等しいかどうかを判定する演算子だ。 ===は2つの値が等しい場合にtrueを返し、等しくない場合にfalseを返す。

通常の等価演算子(==、!=)が比較の際に左右のオペランドの型を自動的に比較可能なものへ変換するのに対し、こちらの厳密等価演算子は比較の際に型の変換をおこなわない。

「等しくない」かどうかを判定したい場合は!==を使用する。 !==は2つの値が等しくない場合にtrueを返し、等しい場合にfalseを返す。

このMDNのページではその仕様について以下のように説明している。

  • オペランドの型が異なる場合は、false を返します。
  • 両方のオペランドがオブジェクトである場合、同じオブジェクトを指している場合に限り true を返します。
  • 両方のオペランドが null または両方のオペランドが undefined であった場合は true を返します。
  • どちらかのオペランドが NaN であった場合は false を返します。
  • それ以外の場合は、2つのオペランドの値を比較します。
    • 数値型は同じ値の数値である必要があります。+0 と -0 は同じ値と見なされます。
    • 文字列型は同じ文字が同じ順序で並んでいる必要があります。
    • 論理型は両方が true であるか両方が false である必要があります。
厳密等価 (===) - JavaScript | MDN

ここに書かれていることを正しく理解すれば誤解は生じないのだが、一部直感に反するような仕様があるため誤った理解をしている人もしばしば見受けられる。 以下では勘違いしやすい点やわかりにくい点について重点的に解説していきたい。

厳密等価演算子の簡単な例

解説の前に厳密等価演算子を使用した比較の簡単な例を示す。

中には「なぜこれがこの結果になるのか」と疑問に感じるものがあるかもしれない。 そう感じた場合は厳密等価演算子の仕様について誤解している可能性が高い。 今一度正しい仕様を確認する必要があるだろう。

等しいと判定される場合

JavaScript
123 === 123; // true "123" === "123"; // true 123 === Number("123"); // true true === true; // true null === null; // true undefined === undefined; // true let a = { value: 123 }; let b = { value: 123 }; a === a; // true b === b; // true

等しくないと判定される場合

JavaScript
123 === "123"; // false 123 === new Number(123); // false 0 === true; // false 1 === true; // false "" === false; // false null === undefined; // false NaN === NaN; // false let a = { value: 123 }; let b = { value: 123 }; a === b; // false

通常の等価演算子ではtrueと判定されていた組み合わせも、厳密等価演算子では型が異なる時点で全てfalseと判定される。

オブジェクト同士の比較

比較されるのは中身ではなくオブジェクトそのもの

JavaScript
let a = { value: 123 }; let b = { value: 123 }; a === a; // true b === b; // true a === b; // false

オブジェクト同士の比較ではオブジェクトそのものが同じものであるかどうかを判定するため、中身が全く同じだとしてもオブジェクトそのものが異なる場合は「等しくない」と判定される。

よくオブジェクトは入れ物と中身に例えられる。 上の例で言えば、aとbが持つ値はどの入れ物かという情報であり、それぞれの入れ物の中に{ value: 123 }という中身が入っている状態だ。 ここでa === bという比較は入れ物が同じかどうかを比較しているため、異なる入れ物であると判定されているわけだ。

それを踏まえた上で次の例を見てもらいたい。

JavaScript
let a = { value: 123 }; let b = { value: 123 }; let c = a; a === c; // true ※ a と c は入れ物が同じ b === c; // false ※ b と c は入れ物が異なる

このようにaの値をcに代入した場合、aとcは同じ入れ物を指すこととなり等しいと判定される。

プリミティブ型とオブジェクトラッパー型の比較

プリミティブ型とオブジェクトラッパー型は異なる型と判定される

JavaScript
1 === 1; // true 1 === new Number(1); // false "ABC" === "ABC"; // true "ABC" === new String("ABC"); // false true === true; // true true === new Boolean(true); // false

JavaScriptでは数値や文字列などのプリミティブ型に対応するオブジェクトラッパー型が定義されているものがある。 文字列ならString型、数値ならNumber型、長整数ならBigInt型、論理値ならBoolean型といったものだ。

これらはプリミティブ型とオブジェクトラッパー型で同じ値を表現することはできるが、厳密等価演算子で比較すると型が違うため「等しくない」と判定される。

オブジェクトラッパー型同士の比較にも注意

JavaScript
let a = new Number(1); let b = new Number(1); let c = a; a === a; // true b === b; // true a === b; // false a === c; // true b === c; // false

オブジェクトラッパー型を使用して数値や文字列を表すこともできるが、それらを厳密等価演算子で比較すると単にオブジェクトとして比較されてしまう。 前項で説明した通り、オブジェクト同士の比較はオブジェクトそのものが同じかどうかで判定される。

JavaScript
function Test(key) { if (key === "12345") return "OK"; return "FAILED"; } let key = new String("12345"); let result = Test(key); // result : "FAILED"

この仕様を正しく理解していないとこのような失敗を招く可能性もある。

Test()関数の中では与えられたkeyがプリミティブ型の文字列である"12345"と等しいかどうかを判定している。 しかしその関数を呼び出す際に与えられた引数がもしオブジェクトラッパー型のnew String("12345")だった場合、それはプリミティブ型の"12345"とは異なるものと判定される。

オブジェクトラッパー型のコンストラクタと変換関数の違い

少し本題からは逸れるが、ここでオブジェクトラッパー型のコンストラクタと変換関数について触れておきたい。 以下は数値におけるNumber型のコンストラクタとNumber()関数で説明するが、文字列や論理値についても同様だ。

オブジェクトラッパー型のコンストラクタは次のようなものだ。

JavaScript
let a = new Number(123); // 123 let b = new Number("500"); // 500 let c = new Number(true); // 1 let d = new Number("abc"); // NaN

引数に与えられた値をNumber型のオブジェクトに変換することができる。 数値に変換できない値が渡された場合はNaNが返される。

次に変換関数の例を示す。

JavaScript
let a = Number(123); // 123 let b = Number("500"); // 500 let c = Number(true); // 1 let d = Number("abc"); // NaN

こちらも引数に与えられた値を数値に変換するが、返されるのはNumber型のオブジェクトではなくプリミティブ型の数値だ。

この違いによって、これらの値を厳密等価演算子で比較する際は以下のような結果になる。

JavaScript
1 === Number(1); // true 1 === new Number(1); // false Number(1) === new Number(1); // false 1 === Number(new Number(1)); // true Number(1) === Number(new Number(1)); // true new Number(1) === new Number(1); // false

比較対象がいずれもプリミティブ型の場合は直感に沿った結果となるが、いずれかまたは両方がオブジェクト型の場合は注意が必要だ。

NaNとの比較

NaN(Not-A-Number)は数値ではない状態を表す特殊な値だ。 このNaNを別の値と比較した場合、対象の値がなんであれ常に「等しくない」と判定される。 これはNaN同士を比較した場合も等しくないと判定されるということだ。

JavaScript
1 === NaN; // false "A" === NaN; // false NaN === NaN; // false ※ここに注意

逆に!==で「等しくないかどうか」を判定する場合は常に結果はtrueになるということだ。

JavaScript
1 !== NaN; // true "A" !== NaN; // true NaN !== NaN; // true ※ここに注意

この仕様については厳密等価演算子だけでなく、通常の等価演算子でも同様となっている。 少々癖のある仕様なのでしっかりと把握しておきたい。

キーワード
JavaScript
シェアする
サイトマップ SITEMAP 広告 写真 PHOTO
年度
2024 2023 2022 2021 2020 2019 2018 2017 ~2016
アルバム
傑作選 北海道 石鎚山系 ネパール 屋久島 北アルプス 中央アルプス 丹沢 離島 巨樹
写真の一覧へ
ストックフォトで作品を探す
旅 JOURNEY
2020年 冬の屋久島歩き旅
2019年 厳冬期北海道徒歩横断
旅の一覧へ
ブログ BLOG
カテゴリ
写真 旅 よもやま話
タグ
スポット 道具 心得
ブログの一覧へ
開発室 DEVELOPMENT
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web
開発室の一覧へ
広告
サイトマップ SITEMAP
スタジオ旅路
https://tabiji.gallery
渡邊 佑
tabiji.gallery (c) 2020 Yu Watanabe サイトマップ SITEMAP 写真 PHOTO
年度
2024 2023 2022 2021 2020 2019 2018 2017 ~2016
アルバム
傑作選 北海道 石鎚山系 ネパール 屋久島 北アルプス 中央アルプス 丹沢 離島 巨樹
写真の一覧へ
ストックフォトで作品を探す
旅 JOURNEY
2020年 冬の屋久島歩き旅
2019年 厳冬期北海道徒歩横断
旅の一覧へ
ブログ BLOG
カテゴリ
写真 旅 よもやま話
タグ
スポット 道具 心得
ブログの一覧へ
開発室 DEVELOPMENT
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web
開発室の一覧へ