誰もが知っているように、== in javaScriptは比較的複雑な操作です。その運用ルールは非常に奇妙であり、簡単に間違いを犯す可能性があり、JavaScriptの「最悪の機能」の1つになります。
ECMAScriptの仕様を注意深く読むことに基づいて、写真を描きました。この写真を理解した後、==操作に関するすべてを完全に理解すると思いました。同時に、私はこの記事を通して、==はそれほど悪いことではないことをすべての人に証明しようとしました。マスターするのは簡単で、合理的でさえ見え、それほど悪くはありません。
まず、写真:
==操作ルールの正確な説明はこちら:抽象的な平等比較アルゴリズム。しかし、このような複雑な説明では、読んだ後にめまいがすることはありませんか?すぐに練習を導くために使用できますか?
確かにうまくいきません。結局のところ、この仕様は、言語のユーザーではなく、JavaScriptランニング環境の開発者向けです(V8エンジンの開発者と比較)。上の写真は、仕様を誰もが見るのに便利なフォームに変換されます。
図1に各部品を詳細に導入する前に、JSのタイプに関する知識を確認しましょう。
JSには、基本タイプとオブジェクトタイプの2つのタイプがあります。
基本的なタイプには、未定義、ヌル、ブール、数字、文字列が含まれます。
未定義のタイプとヌルタイプの両方には、1つの値、つまり未定義とnullのみがあります。ブールタイプには2つの値があります。数値タイプには多くの値があります。文字列型には無数の値があります(理論的に)。
すべてのオブジェクトには、valueof()およびtoString()メソッドがあり、オブジェクトから継承され、もちろんサブクラスによって書き換えられる場合があります。
次に、表現を考えてみましょう。
x == y
ここで、xとyは6つのタイプのいずれかの値です。
xとyのタイプが同じ場合、x == yはx === yに変換でき、後者は非常に単純です(注意すべき唯一のものはnan)ので、xとyのタイプが異なる場合のみを考慮します。
1。持っていない
図1では、6種類のJavaScript値が青色の背景を持つ長方形で表されます。最初にそれらは2つのグループに分かれています。
文字列、数字、ブール、オブジェクト(左側の大きな長方形のボックスに対応)
未定義でヌル(右側の長方形のボックスに対応)
グループ化の基礎は何ですか?見てみましょう。右側の未定義でヌルは、不確実性を示すために使用されますが、非または空ではありませんが、右側の4つのタイプはすべて決定され、既存および非空白です。私たちはこれを言うことができます:
左側には存在の世界があり、右側には空の世界があります。
したがって、2つの世界の価値をfalseと比較することは合理的です。 (つまり、図1の2つの長方形を接続する水平線はfalseとマークされています)
2。空と空
JavaScriptの未定義でヌルは、しばしば私たちをクラッシュさせる別の場所です。通常、それは設計上の欠陥と見なされますが、それは私たちが掘り下げません。しかし、私はJavaScriptの著者が最初にこれを考えたと聞いたことがあります:
オブジェクトタイプの値に変数を割り当てるが、まだ値を割り当てていない場合は、NULLを使用して現時点で状態を表すことができます(TypeOf Nullの結果は「オブジェクト」であるという証拠です)。それどころか、元のタイプの値に変数を割り当てることを計画しているが、まだ値を割り当てていない場合は、現時点では未定義を使用して状態を表すことができます。
この噂が信頼できるかどうかに関係なく、2つの比較の結果が真実であることが合理的です。 (つまり、図1の右側の垂直線にマークされた真)
次のステップに進む前に、図1の2つのシンボルについて説明しましょう:大文字nとPの2つのシンボルは、PNセクションで正とネガティブを意味しません。その代わり:
nはトナンバー操作を表します。これは、オペランドを数値に変換することを意味します。これはES仕様の抽象操作ですが、JSの数字()関数を使用して同等に置き換えることができます。
Pは、トップリミティブ操作、つまりオペランドを元のタイプの値に変換することを表します。また、ES仕様の抽象操作であり、同等のJSコードに翻訳することもできます。しかし、それはもう少し複雑です。簡単に言えば、オブジェクトのOBJの場合:
TopRimiTive(OBJ)は次のものと同等です。最初にOBJ.ValueOf()を計算します。結果が元の値である場合、この結果は返されます。それ以外の場合、obj.toString()が計算され、結果が元の値である場合、この結果が返されます。それ以外の場合、例外がスローされます。
注:ここには例外、つまりタイプの日付のオブジェクトがあり、最初にtoString()メソッドを呼び出します。
図1では、nまたはpとマークされた線は、2種類のデータが==操作を実行するために接続されている場合、nまたはpのマークされた側面のオペランドが最初にトニウムまたは最低変換を実行する必要があることを示しています。
3。真と偽
図1からわかるように、ブール値が他のタイプの値と比較されると、ブール値は数に変換されます。具体的には
TRUE-> 1
false-> 0
これには、あまりにも多くの言葉による虐待は必要ありません。考えてみてください。Cでは、ブールタイプはまったくありません。整数1および0は、通常、真または偽のロジックを表すために使用されます。
IV。文字のシーケンス
図1では、弦と数値をグループに分割します。なぜ? 6つのタイプの中で、文字列と数字は文字のシーケンスです(少なくとも文字通り)。文字列はすべてのリーガルキャラクターのシーケンスであり、数字は特定の条件を満たす文字のシーケンスと見なすことができます。したがって、数字は文字列のサブセットと見なすことができます。
図1によると、文字列と数字の==操作を実行する場合、Tonumber操作を使用して文字列を数字に変換する必要があります。 xが文字列であり、yが数字であると仮定します。
x == y-> number(x)== y
それでは、文字列を数字に変換するためのルールは何ですか?仕様は非常に複雑な方法で説明されていますが、一般的に言えば、文字列の両側の引用符を削除し、法的番号を形成できるかどうかを確認することです。もしそうなら、変換の結果はこの数です。それ以外の場合、結果はnanです。例えば:
番号( '123')//結果123
番号( '1.2e3')//結果1200
number( '123abc')// result nan
もちろん、空の文字列を数字に変換した結果は0です。
番号( '')//結果0
V.シンプルで複雑
プリミティブタイプはシンプルなタイプであり、簡単で理解しやすいです。ただし、不利な点は、表現能力が限られており、拡張が困難であるため、オブジェクトがあることです。オブジェクトは属性のコレクションであり、属性自体はオブジェクトになります。したがって、オブジェクトは、さまざまなものを表現するのに十分なほど任意に複雑に構築できます。
しかし、時には物事が複雑であり、良いことではありません。たとえば、誰もが時間、忍耐、または最初から最後まで読む必要性を持っているわけではありません。通常、その中心的な考えのみを理解するだけで十分です。そのため、このペーパーにはキーワードと概要があります。 JavaScriptのオブジェクトにも同じことが言えます。その主な特性を理解するための手段が必要であるため、オブジェクトにはtoString()およびvalueof()メソッドがあります。
toString()メソッドは、オブジェクトのテキスト説明を取得するために使用されます。値()メソッドは、オブジェクトの固有値を取得するために使用されます。
もちろん、これは私自身の理解です。また、名前が示すように、toString()メソッドは文字列を返す傾向があります。 valueof()メソッドはどうですか?仕様の説明によると、数値を返す傾向があります - 組み込みのタイプでは、値()メソッドは数と日付のみを返します。
図1によれば、オブジェクトが非オブジェクトと比較される場合、オブジェクトはプリミティブタイプに変換する必要があります(ただし、ブール型と比較する場合、ブール型タイプを最初に数値タイプに変換する必要がありますが、オブジェクトタイプは次に原始タイプに変換する必要があります)。これも合理的です。結局のところ、==は厳密に平等な比較ではありません。操作に参加するには、オブジェクトの主な機能を取り出し、二次機能を脇に置くだけです。
六。すべてがカウントされます
図1を振り返ってみましょう。内部のnまたはpとマークされた線には方向がありません。これらの行の矢印をマークすると、端からnまたはpをもう一方の端にマークする接続ポイントが得られます(未定義でnullを考慮しないでください)。
何か発見しましたか?はい、計算プロセス中に、すべてのタイプの値は数値タイプに変換する傾向があります。結局のところ、有名人はかつて言った:
すべてがカウントされます。
7.栗をください
過去にはあまりにも多くのナンセンスがあるので、図1が実際に実践を導くのに便利で効果的であることを証明する例を以下に示します。
たとえば、以下を計算します。
[''] == false
まず、2つのオペランドはそれぞれオブジェクトタイプとブール型です。図1によると、ブール型を数値タイプに変換する必要があり、falseを数値に変換した結果は0であるため、式は次のようになります。
[''] == 0
2つのオペランドは、オブジェクトタイプと数値タイプになります。図1によると、オブジェクトタイプは元のタイプに変換する必要があります。
最初に、[] .valueof()を呼び出します。配列のvalueof()メソッドはそれ自体を返すため、結果は元のタイプではありません。 [] .toString()を呼び出し続けます。
配列の場合、toString()メソッドのアルゴリズムは、各要素を文字列型に変換し、「」で順番に連結するため、最終結果は元の型の値である空の文字列です。
この時点で、式は次のようになります。
'== 0
2つのオペランドは、文字列タイプと数値タイプになります。図1によると、文字列タイプは数値型に変換する必要があります。前述のように、空の文字列は多くの0になります。したがって、式は次のようになります。
0 == 0
これまでのところ、2つのオペランドのタイプは最終的に同じであり、結果は明らかに真実です。
この例から、図1を覚えていることに加えて、==操作のルールを習得するために、これらの組み込みオブジェクトのtoString()およびvalueof()メソッドのルールを覚えておく必要があることがわかります。オブジェクト、配列、日付、番号、文字列、ブールンなどを含む。
8。要約しましょう
前の声明は非常に混乱しています。ここでは、図1に表明された==操作のルールを要約します。
未定義の== nullの結果は真です。他のすべての値との比較の結果は偽です。
文字列==番号の場合、文字列は数値に変換されます。
ブール値==他のタイプを使用すると、ブール値は数に変換されます。
オブジェクト== numeric/文字列の場合、オブジェクトはプリミティブタイプに変換されます。
最後に、私は写真をエンターテイメントのみに変えました:)
わかりました、それは終わりました。この記事があなたにとって役立つと思うなら、もっと多くの人がそれを見ることができるようにそれを気に入ってください。
さらに、記事の誤りを指摘してください。