ホームページ >ウェブフロントエンド >jsチュートリアル >邪悪な双子を恐れないでください - setepoint

邪悪な双子を恐れないでください - setepoint

Jennifer Aniston
Jennifer Anistonオリジナル
2025-02-22 08:58:11890ブラウズ

Don't Fear the Evil Twins - SitePoint

JavaScript開発者のDouglas Crockfordは、かつてJavaScript ==およびオペレーターを避けるべき「邪悪な双子」と呼んでいました。ただし、それらを理解すると、これらのオペレーターはそれほど悪くなく、実際に有用になる可能性があります。この記事では、!===を調べ、それらがどのように機能するかを説明し、それらをよりよく理解するのに役立ちます。 !=

キーポイント

  • 基本を理解する:JavaScriptの演算子は、さまざまなタイプの値を比較するときに、本質的に悪ではありません。 ==キャストなしの直接的なタイプと値の比較には、いつ使用するかを使用してください。タイプが動的に変更される可能性のある値をキャストまたは比較する必要がある場合は、!=および
  • を使用します。
  • キャストルールを学びます:===および!==比較の間にJavaScriptがどのようにタイプをキャストするかに精通しているため、結果をより正確に予測し、一般的な落とし穴を回避します。 == !=
  • 実用的な例を探索します。 恐れないでください。しかし注意してください:==!=とは恐ろしくありませんが、JavaScriptのタイプキャストルールを効果的かつ安全であるために使用するためには、それを使用するために十分に理解する必要がありますローカル。
  • ==問題!=javaScript言語には、
  • 、およびの2セットの平等演算子が含まれています。平等オペレーターのセットが2つある理由と、どのオペレーターが多くの人々にとって混乱の原因となった状況があるのか​​を理解してください。 ==および!=オペレーターを理解するのは難しくありません。 2つのオペランドタイプが同じで、値が同じである場合、
および

を返し、を返します。ただし、値またはタイプが異なる場合、==を返し、!=を返します。 2つのオペランドタイプが同じ場合、

および

演算子は同じように動作します。ただし、タイプが異なる場合、JavaScriptは1つのオペランドを別のタイプにキャストして、比較前にオペランドを互換性のあるものにします。結果は、次のようにしばしば混乱しています === !==可能なブール値は2つしかないため、式の1つを==として計算する必要があると思うかもしれません。ただし、それらはすべて!=として計算されます。パス関係(aがbに等しく、bがcに等しい場合)が適用する必要があると仮定すると、追加の混乱が発生します。

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

この例は、==にトランサテン性が欠けていることを示しています。空の文字列が番号0に等しく、数値0が文字0で構成される文字列に等しい場合、空の文字列は0で構成される文字列に等しくなければなりません。しかし、そうではありません。オペランドを==または!=を介してオペランドを比較するときに互換性のないタイプに遭遇した場合、JavaScriptは1つのタイプを別のタイプにキャストして、比較可能にします。逆に、===!==を使用すると、タイプキャストを実行することはありません(パフォーマンスのわずかな改善につながります)。さまざまな種類のため、===は常に2番目の例でfalseを返します。 JavaScriptがオペランドをさまざまなタイプにキャストする方法を制御するルールを理解するため、2つのオペランドタイプが適用する前に2つのオペランドタイプが互換性があるようにすることができます。これらの演算子を使用します。次のセクションでは、==および!=オペレーターで使用されるキャストルールを検討します。 == != ==!=および

はどのように機能しますか?

==!=の作業が、ECMAScript言語の仕様をどのように研究するかを学ぶための最良の方法です。このセクションでは、ECMAScript 262に焦点を当てています。仕様のセクション11.9では、平等演算子を紹介します。 および

演算子は、構文生成

および==に表示されます。 (第一世代とは異なり、第2世代は!=演算子を回避します。)以下に示す==世代を確認しましょう。 != EqualityExpression EqualityExpressionNoInこの世代によれば、等しい式はリレーショナル式、またはリレーショナル式に等しい等しい式、またはリレーショナル式などに等しくない等しい式のいずれかです。 (私はこの記事に関連していないinEqualityExpressionを見落としていました。)セクション11.9.1は、

の仕組みに関する以下の情報を提供します。
<code class="language-javascript">'' == 0   // true
0 == '0' // true
'' == '0' // false</code>

生産式==は次のように計算されます != === !==を計算の結果とします。 ==

let
be

EqualityExpression : EqualityExpression == RelationalExpression

    を計算の結果とします。
  1. lref letEqualityExpressionbe
  2. lval抽象的な平等比較を実行した結果を返しますGetValue(lref)。 (11.9.3を参照してください。)
  3. rref RelationalExpressionセクション11.9.2は、どのように機能するかについての同様の情報を提供します:
  4. rval生産式GetValue(rref)は次のように計算されます
    1. lrefを計算の結果とします。 EqualityExpression
    2. let
    3. belvalGetValue(lref)
    4. を計算の結果とします。 rref RelationalExpression let
    5. be
    6. rval GetValue(rref)
    7. 抽象的な平等比較を実行した結果とする
    8. とします。 (11.9.3を参照してください。)r rval != lvalif
    9. is
    10. 、returnr。それ以外の場合は、trueを返します。 false true
および

は、lrefおよびrrefオペレーターの左側と右側に参照されます。各参照は、対応する値を返すために==内部関数に渡されます。セクション11.9.3:!=に示されている抽象的な平等比較アルゴリズムによって、GetValue()および==作業がどのように指定されているかの中核 !=

比較
、ここで

x == yは値であり、xまたはyになります。この比較は、次のように実行されます:true

  1. Type(x)Type(y)と同じ場合、
    1. ifType(x)isUndefined、returntrue
    2. ifType(x)isNull、returntrue
    3. if Type(x) isNumber、次に
      1. ifxisNaN、returnfalse
      2. ifyisNaN、returnfalse
      3. xおよびyが同じ数値値である場合、trueを返します。
      4. xの場合、yは0、trueは-0、return
      5. です。
      6. xyが-0、trueが0の場合、
      7. が返されます。
      8. falsereturn
    4. Type(x)Stringisxである場合、yおよびtrueがまったく同じ文字シーケンス(対応する位置の同じ長さと同じ文字)である場合、falseが返されます。それ以外の場合は、
    5. を返します。
    6. Type(x)ifBooleanの場合、xyの両方である場合、または両方の場合、trueの両方である場合、falseを返します。それ以外の場合は、trueを返します。 false
    7. 同じオブジェクトを参照している場合、
    8. およびxを参照してくださいy。それ以外の場合は、trueを返します。 false
  2. if
  3. isxおよびnullisyundefinedを返します。 true
  4. if
  5. isxおよびundefinedisynullを返します。 true
  6. isType(x)andNumberisType(y)の場合、比較の結果が返されます。 String x == ToNumber(y)
  7. is
  8. andType(x)isStringの場合、比較の結果が返されます。 Type(y) NumberToNumber(x) == yの場合、
  9. の場合、比較の結果が返されます。
  10. Type(x)Booleanの場合、ToNumber(x) == yの場合、比較の結果が返されます。
  11. Type(y)isBooleanまたはx == ToNumber(y)および
  12. is
  13. の場合、比較の結果が返されます。 Type(x) StringNumberisType(y)andObjectisx == ToPrimitive(y)または
  14. の場合、比較の結果が返されます。
  15. Type(x)returnObjectType(y) String Number ToPrimitive(x) == yステップ1オペランドタイプは、このアルゴリズムで実行されると同じです。
  16. に等しく、false
  17. に等しいことを示しています。また、NaN(非番号)、2つの同一の値が等しく、0は0に等しい、同じ長さの2つの文字列が等しいものは等しいものは等しく、truetruefalseに等しく、同じオブジェクトへの2つの参照が等しくなります。手順2と3は、falseを返す理由を示します。 JavaScriptは、これらの値が同じであると考えています。ステップ4から始めて、アルゴリズムが興味深いものになります。このステップでは、null != undefined値とfalse値の平等に焦点を当てています。最初のオペランドがNumberであり、2番目のオペランドがStringである場合、2番目のオペランドはNumberの内部関数を介してStringに変換されます。式ToNumber()は再帰を意味します。ステップ5はステップ4に相当しますが、最初のオペランドにはタイプNumberがあり、型x == ToNumber(y)に変換する必要があります。手順6および7ブールオペランドをStringタイプに変換して再帰的に変換します。他のオペランドがブール値である場合、このアルゴリズムが次に実行されるときにNumberに変換され、再び再発します。パフォーマンスの観点から、2つの再帰的な手順を避けるために、両方のオペランドがブール型であることを確認することをお勧めします。ステップ9は、オペランドのタイプがNumberの場合、オペランドがNumber内部関数を介して元の値に変換され、アルゴリズムが再帰的に変換されることを示しています。最後に、アルゴリズムは、2つのオペランドが等しくなく、ステップ10でObjectを返すことを考慮します。詳細ではありますが、抽象的な平等比較アルゴリズムは非常に簡単に理解できます。ただし、アルゴリズムを完全に理解するために内部作業を公開する必要がある内部関数のペアを参照しています。 ToPrimitive()関数は、そのパラメーターをfalseに変換し、セクション9.3で説明します。次のリストは、考えられる非数字のパラメーターと同等の返品値をまとめたものです。
  • パラメーターがUndefinedの場合、NaNを返します。
  • パラメーターがNullの場合、0を返します。
  • パラメーターがブール値trueの場合、1を返します。パラメーターがブール値falseの場合、0を返します。
  • パラメータータイプがNumberの場合、入力パラメーターが返されます - 変換はありません。
  • パラメーターのタイプがStringの場合、セクション9.3.1「文字列タイプのトナンバー」が適用されます。構文で示される文字列パラメーターに対応する値を返します。パラメーターが示されている構文と一致しない場合は、NaNを返します。たとえば、パラメーター「xyz」はNaNを引き起こします。さらに、パラメーター「29」の結果、29が返されます。
  • パラメーターのタイプがObjectの場合、次の手順を適用してください。
      let
    1. beprimValueToPrimitive(输入参数, 提示Number)
    2. return
    3. ToNumber(primValue)

関数は、入力パラメーターとオプションのToPrimitive()パラメーターを受け入れます。入力パラメーターは、非オブジェクトタイプに変換されます。オブジェクトを複数のプリミティブタイプに変換できる場合は、PreferredTypeオプションのToPrimitive()プロンプトを使用して、優先タイプにバイアスをかけます。コンバージョンは次のように実行されます:PreferredType

    入力パラメーターが
  1. の場合、入力パラメーター(Undefined)が返されます - 変換はありません。 Undefined
  2. 入力パラメーターが
  3. の場合、入力パラメーター(Null)が返されます - 変換はありません。 Null
  4. 入力パラメーターのタイプが
  5. の場合、入力パラメーターを返します - 変換はありません。 Boolean
  6. 入力パラメーターのタイプが
  7. の場合、入力パラメーターを返します - 変換はありません。 Number
  8. 入力パラメーターのタイプが
  9. の場合、入力パラメーターを返します - 変換はありません。 String
  10. 入力パラメーターのタイプが
  11. の場合、入力パラメーターに対応するデフォルト値が返されます。オブジェクトの内部メソッドを呼び出し、オプションのObjectプロンプトを渡すことにより、オブジェクトのデフォルト値を取得します。 [[DefaultValue]]の動作は、すべてのネイティブECMAScriptオブジェクトのセクション8.12.8で定義されています。 PreferredType [[DefaultValue]] このセクションでは、非常に多くの理論を紹介します。次のセクションでは、
を含むさまざまな表現を提供し、徐々にアルゴリズムの手順を完了することにより、練習に目を向けます。

==!=邪悪な双子を理解してください

ECMAScriptの仕様に従って

がどのように機能するかを理解したので、これらの演算子が関与するさまざまな表現を調査して、この知識を利用してみましょう。これらの表現を評価する方法を説明し、それらが

または==である理由を調べます。私の最初の例については、記事の冒頭の近くで導入された次の式ペアを考えてみましょう。 != true抽象的な平等比較アルゴリズムに従って、次の手順に従ってこれらの式を評価します。

    タイプが異なるため、
  1. ステップ1をスキップします。typeof "this_is_true" "string"を返し、typeof falseまたはtypeof trueは「boolean」を返します。
  2. 手順2から6をスキップします。これは、オペランドの種類と一致しないために適用できません。ただし、適切なパラメーターにはBooleanがあるため、ステップ7は適用されます。式は"this_is_true" == ToNumber(false)および"this_is_true" == ToNumber(true)に変換されます。
  3. ToNumber(false)は0を返し、ToNumber(true) 1を返します。これにより、式がそれぞれ"this_is_true" == 0および"this_is_true" == 1に単純化されます。この時点で、アルゴリズムは再帰的に。
  4. 手順1から4をスキップします。これは、オペランドの種類と一致しないために適用できません。ただし、ステップ5は、左オペランドのタイプがStringであり、右オペランドのタイプがNumberであるために適用されます。式はToNumber("this_is_true") == 0およびToNumber("this_is_true") == 1に変換されます。
  5. ToNumber("this_is_true")NaNを返します。これは、それぞれNaN == 0NaN == 1に式を簡素化します。この時点で、アルゴリズムは再帰的に。
  6. ステップ1に移動します。これは、NaN、0、および1のタイプがすべてNumberであるためです。適用されない手順1.aおよび1.bをスキップします。ただし、ステップ1.C.は、左のオペランドがNaNであるために適用されます。アルゴリズムは、各元の式の値としてfalseNaNはそれ自体を含むものと等しくない)を返すようになり、スタックをバックトラックして再帰を完全に終了します。

私の2番目の例(「Galaxy Wandering Guide」での人生の意味の説明に基づいて)は、==true

の数字とオブジェクトを比較します。
<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

次の手順では、JavaScriptが抽象的な等式比較アルゴリズムを使用して式の値として取得する方法を示しています。

  1. 手順1から8をスキップします。これは、オペランドの種類と一致しないために適用できません。ただし、ステップ9は、左オペランドのタイプがObjectであり、右オペランドのタイプがNumberであるために適用されます。式はToPrimitive(lifeAnswer) == 42に変換されます。
  2. ToPrimitive()プロンプトなしでlifeAnswer内部メソッドを呼び出してください。 ECMAScript 262仕様のセクション8.12.8によれば、[[DefaultValue]]は「42」を返す[[DefaultValue]]メソッドを呼び出します。式はtoString()に変換され、アルゴリズムは再帰的です。 "42" == 42
  3. 手順1から4をスキップします。これは、オペランドの種類と一致しないために適用できません。ただし、ステップ5は、左オペランドのタイプが
  4. であり、右オペランドのタイプがStringであるために適用されます。式はNumberに変換されます。 ToNumber("42") == 42
  5. は42を返し、式はToNumber("42")に変換されます。アルゴリズムは、ステップ1.C.IIIを再発および実行します。数字は同じであるため、42 == 42が返され、再帰的に拡張されます。 true
私の最後の例では、次のシーケンスがトランジニティを示さない理由を調べましょう。

true次の手順では、JavaScriptが抽象的な等式比較アルゴリズムを使用してfalseの値として取得する方法を示しています。

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

ステップ5を実行してtrueになり、'' == 0に変換され、アルゴリズムが再帰的に変換されます。 (仕様のセクション9.3.1では、

String -numericLiteral ::: [empty] 's mv [数学的値]は0です。つまり、空の文字列の値は0です。)
  1. ステップ1.C.IIIを実行します。これは、0を0と比較し、ToNumber('') == 0を返します(および再帰を展開します)。 0 == 0 次の手順では、JavaScriptが抽象的な等式比較アルゴリズムを使用して
  2. の値として取得する方法を示しています。 true
  3. ステップ4を実行して
になり、

に変換され、アルゴリズムが再帰的に変換されます。 true 0 == '0'ステップ1.C.IIIを実行します。これは、0を0と比較し、

を返します(および再帰を展開します)。
  1. 0 == ToNumber('0')最後に、javaScriptは抽象的な等式比較アルゴリズムでステップ1.dを実行して、0 == 0の値として
  2. を取得します。 2つの文字列の長さは異なるため(0と1)、
  3. を返します。 true
結論

true '' == '0' false

を使用する必要がある理由を疑問に思うかもしれません。結局のところ、以前の例では、これらの演算子は、型鋳造と再帰のために

およびオペレーターよりも遅くなる可能性があることが示されています。場合によっては利点がないため、および

を使用することをお勧めします。次の例を考えてみましょう:

<code class="language-javascript">"this_is_true" == false // false
"this_is_true" == true  // false</code>

typeof演算子はString値を返します。 String値は別のString値( "オブジェクト")と比較されるため、型キャストは発生しません。たぶん、==に遭遇したことがないJavaScriptの初心者は、そのようなコードがより明確になるでしょう。同様に、次のコードスニペットではタイプキャストを必要としません(両方のオペランドのタイプは===)ため、===Number!=と同じくらい効率的です。 !==

これらの例は、
<code class="language-javascript">'' == 0   // true
0 == '0' // true
'' == '0' // false</code>

が鋳造を必要としない比較に適していることを示しています。オペランドのタイプが異なる場合、==および!=が予期しない値ではなく===を返すため、最良の選択です(例:!==false)。オペランドのタイプが同じ場合、false == ""およびtrueを使用しない理由はありません。たぶんそれは邪悪な双子を恐れるのをやめる時であり、あなたがそれらを理解したら、彼らは邪悪ではありません。 == JavaScriptの平等と比較演算子(FAQ)!=

のFAQ javascriptの

の違いは何ですか?

JavaScriptでは、

および==は比較演算子です。ただし、値を比較する方法が異なります。 ===オペレーター(ルーズ平等演算子とも呼ばれます)は、比較前にタイプキャストを実行します。これは、2つの異なるタイプの値を比較する場合、JavaScriptは比較を実行する前に1つのタイプを別のタイプに変換しようとすることを意味します。一方、

オペレーター(厳密な平等演算子と呼ばれる)は、型キャストを実行しません。値とタイプを同時に比較します。つまり、2つの値タイプが異なる場合、JavaScriptはそれらが不平等であると見なされます。

== javascriptで===の代わりに==を使用する必要があるのはなぜですか? === JavaScriptでは、

の代わりに

の代わりに===を使用することをお勧めします。これは、より厳格な比較を提供するためです。つまり、タイプのキャストと値とタイプのチェックを実行しないことを意味します。これは、さまざまなタイプの値を比較する場合、予期しない結果を回避するのに役立ちます。たとえば、JavaScriptは==を使用する場合、数値0と空の文字列「「等しい」と見なされます。これは、比較前にタイプを変換するためです。ただし、

を使用すると、それらは異なるタイプであるため、不平等と見なされます。

=== javascriptのタイプキャストとは何ですか? == JavaScriptの型キャストとは、あるデータ型から別のデータ型に自動または暗黙的に変換されることを指します。これは、オペレーターがさまざまな種類のオペランドに使用されている場合、または何らかのタイプが必要な場合に発生します。たとえば、ゆるい平等オペレーター(==)を使用する場合、JavaScriptは比較する前にオペランドを一般型に変換しようとします。 ===

JavaScriptはオブジェクトの比較をどのように処理しますか?

javascriptでは、オブジェクトは値ではなく参照によって比較されます。これは、2つのオブジェクトがまったく同じプロパティと値を持っていても、メモリ内の異なるオブジェクトを参照するため、等しいとは見なされないことを意味します。オブジェクトが等しいと見なされる唯一のケースは、まったく同じオブジェクトを参照することです。

javascriptの

==!=の違いは何ですか?

==および!=は、JavaScriptの比較演算子です。 ==オペレーターは、2つのオペランドの値が等しいかどうかを確認し、必要に応じてタイプキャストを実行します。一方、!=オペレーターは、2つのオペランドの値が等しくないかどうかを確認し、必要に応じてタイプキャストを実行します。

javascriptの

===!==の違いは何ですか?

===および!==は、JavaScriptの比較演算子です。 ===演算子は、値とタイプの両方を考慮して、2つのオペランドの値が等しいかどうかを確認します。一方、!==演算子は、値とタイプの両方を考慮して、2つのオペランドの値が等しくないかどうかをチェックします。

JavaScriptの2つの配列を比較する方法は?

javascriptでは、アレイはオブジェクトであり、値ではなく参照によって比較されます。つまり、2つの配列に同じ順序で同じ要素が含まれていても、メモリ内の異なるオブジェクトを参照するため、等しいとは見なされません。コンテンツで2つの配列を比較するには、各要素を個別に比較する必要があります。

javaScriptはnullundefinedの比較をどのように処理しますか?

JavaScriptでは、

およびnullは、両方とも欠損値を表しているため、ゆるく等しい(undefined)と見なされます。ただし、タイプが異なるため、厳密に等しくありません()。 == === JavaScriptの比較演算子の優先順位は何ですか?

JavaScriptでは、比較演算子の優先度レベルと同じです。それらは左から右に計算されます。ただし、算術演算子やビットワイズ演算子よりも優先度が低いが、論理演算子よりも高いことに注意することが重要です。

JavaScriptの文字列を使用して比較演算子を使用できますか?

はい、JavaScriptの文字列を持つ比較演算子を使用できます。 JavaScriptは、文字列を比較するときに語彙(辞書)順序を使用します。ただし、大文字は小文字が小さいため、小文字よりも「小さい」と見なされていることに注意することが重要です。

以上が邪悪な双子を恐れないでください - setepointの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:基礎5次の記事:基礎5