web-dev-qa-db-ja.com

JavaScriptの1 == [1]はどうですか?

最近、私はインタビューでこの質問をされました。

 var a = 1;
 var b = [1];

何がa == b;戻る。

私がchromeブラウザコンソールで確認したところ、これがわかりました。

var a = 1;
var b = [1];
a == b;
true

私もチェックしました

var a = 1;
var b =(1);
a == b;
true

サイズ1の配列でbであることを知っています。これは、配列のサイズがbに割り当てられることを意味しますか?私は本当に混乱しています。誰かが私に論理を説明できますか?

38
hmachahary

オブジェクトをプリミティブ値に変換するときにvalueOftoStringがどのように作用するかについては、レイヨンの回答からはよくわかりませんでした。それで、私は ECMAScript 2015 仕様を掘り下げました。

警告:長い答え。

1 == [1]を確認します。

12.10等値演算子から始めて、式の値を取得した後、最後のステップは

  1. 抽象等価比較の実行結果を返しますrval == lval

抽象等値比較は、7.2.12抽象等値比較の章で定義されています。

7.2.12抽象等価比較
x == y(xとyは値)の比較により、trueまたはfalseが生成されます。このような比較は次のように実行されます。

  1. ReturnIfAbrupt(x)。
  2. ReturnIfAbrupt(y)。
  3. Type(x)がType(y)と同じ場合、
    a。完全等価比較x === yを実行した結果を返します。
  4. Xがnullでyが未定義の場合、trueを返します。
  5. Xが未定義でyがnullの場合、trueを返します。
  6. Type(x)がNumberでType(y)がStringの場合、比較の結果x == ToNumber(y)を返します。
  7. Type(x)がStringでType(y)がNumberの場合、ToNumber(x)== yの比較結果を返します。
  8. Type(x)がブール値の場合、比較の結果ToNumber(x)== yを返します。
  9. Type(y)がブール値の場合、x == ToNumber(y)の比較結果を返します。
  10. Type(x)が文字列、数値、または記号のいずれかで、Type(y)がオブジェクトの場合、比較結果を返しますx == ToPrimitive(y)。
  11. Type(x)がObjectで、Type(y)がString、Number、またはSymbolの場合、ToPrimitive(x)== yの比較結果を返します。
  12. Falseを返します。

1 == [1]case 10に該当します。
基本的に、予想どおり、配列[1]はプリミティブ型の値に変換されます。

ToPrimitive7.1.1で定義されますToPrimitive(input [、PreferredType])

抽象演算ToPrimitiveは、入力引数とオプションの引数PreferredTypeを取ります。抽象演算ToPrimitiveは、その入力引数を非オブジェクト型に変換します。

唯一の興味深いこの例の部分は次のとおりなので、完全な引用を含めていません:

  1. PreferredType引数(実際にはhintvar)は、「デフォルト」(渡されないため)から「数値」に変換されます。
  2. OrdinaryToPrimitiveは同じ引数で呼び出されます。

E興味深い部分、OrdinaryToPrimitiveは以下を実行します。

  1. アサート:Type(O)はオブジェクトです
  2. アサート:Type(hint)はStringで、その値は「string」または「number」のいずれかです。
  3. ヒントが「文字列」の場合、
    a。 methodNamesを" "toString"、 "valueOf""にします。
  4. そうしないと、
    a。 methodNamesを" "valueOf"、 "toString""。にします。
  5. リスト順のmethodNamesの各名前に対して、
    a。メソッドをGet(O、name)にします。
    b。 ReturnIfAbrupt(メソッド)。
    c。 IsCallable(method)がtrueの場合、
    ... 私。結果をCall(method、O)とします。
    ... ii。 ReturnIfAbrupt(result)。
    ... iii。 ** Type(result)がObjectではない場合、結果を返します。 **
  6. TypeError例外をスローする

したがって、[1]をプリミティブ値に変換するために、ランタイムは最初にvalueOfを呼び出そうとします。このメソッドは、オブジェクトである配列自体を返すため、5.c.iiiによって、次にメソッドtoStringが呼び出されます。
このメソッドは、配列の要素をコンマ区切りのリストとして返すため、文字列"1"を返すだけです。

したがって、1 == "1"の比較は減少します。これは、Abstract Equality Comparisonの規則によって、ポイント6は"1"を数値1に変換することを意味しますそして、ささいな比較1 = 1を実行するよりも。

疑わしい読者は、厳密な等価比較が実際に標準でどのように定義されているかを確認するよう招待されます。


この変換を試して、理解を深めることができます。ここでは、サンプルのプレイグラウンドHTMLファイルを示します。

<html>
    <head><title>title</title></head>
    <body>
        <script>
            var old_valueOf = Array.prototype.valueOf;
            var old_toString = Array.prototype.toString;

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return old_valueOf.apply(this); };
            Array.prototype.toString = function(){ console.log("Array::toString"); return old_toString.apply(this); };

            console.log(1 == [1]); //Array::valueOf, Array::toString, true 

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return 2; };

            console.log(1 == [1]); //Array::valueOf, false 

            Array.prototype.valueOf = function(){ console.log("Array::valueOf"); return {}; };
            Array.prototype.toString = function(){ console.log("Array::toString"); return {} };

            console.log(1 == [1]); //Array::valueOf, Array::toString, Uncaught TypeError: Cannot convert object to primitive value
        </script>
    </body>
</html>
52
Margaret Bloom

オブジェクトが数値または文字列と比較されると、JavaScriptはオブジェクトのデフォルト値を返そうとします。演算子は、オブジェクトの String および Number メソッドを使用して、オブジェクトをプリミティブ値、valueOfまたはtoString値に変換しようとします。このオブジェクト変換の試みが失敗すると、実行時エラーが生成されます。[ Ref ]

var a = 1;
var b = [1];
//What is happening when `(a==b)`
//typeof a;   ==> number
//typeof b;  ==>object
//Object is converted to Primitive using `valueOf` and `toString` methods of the objects
var val = b.valueOf().toString();
console.log('Values after conversion is: ' + val + '  And typeof converted value is:  ' + typeof val);
//typeof val; ==> string
//a == b; will be evaluated as `true` because `'1' == 1` hence..
console.log(a == b); //'1'==1 ==> true

変換された値はString型であるため、numberstringを比較する場合、stringnumber値に変換されてから、厳密な比較が適用されます。

52
Rayon

これは、行われる比較のタイプによるものです。

JavaScriptでは、比較に_==_または_===_を使用できます。トリプルイコールの場合、これは equalitywithouttype coercion として知られているものです。つまり、厳密な比較です。

型強制との等価

逆に、これは、二重の等号オペランドの使用がwith型強制であることを意味します。

これはどういう意味ですか?

簡単に言うと、JavaScriptは組み込みのメソッドを使用して、値をプリミティブ型に変換し、比較できるようにするということです。具体的には、これらのメソッドは.valueOf()および.toString()です。

ここではいくつかの例を示します。

_0 == false   // true, auto type coercion
0 === false  // false, because they are of a different type
1 == "1"     // true, auto type coercion
1 === "1"    // false, because they are of a different type
_

エルゴ:

_1 == [1] // true
1 === [1] // false, because they are of a different type
_
13
gdgr