web-dev-qa-db-ja.com

JavaScriptの同等性の推移性は奇妙です

私は読んでいます Douglas CrockfordのJavaScript:The Good Parts 、そして私はこの奇妙な例に出くわしました。私にとっての感覚:

'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == undefined  // false
false == null       // false
null == undefined   // true

著者はまた、「==!=を絶対に使用しないでください。代わりに、常に===!==を使用してください」と述べています。しかし、彼はなぜ上記の行動が見られるのか説明していませんか?だから私の質問は、なぜ上記の結果がそのままなのかということです。 JavaScriptでは推移性は考慮されていませんか?

37
Hristo
'' == '0' // false

左側は空の文字列で、右側は1文字の文字列です。 2つの同一でない文字列を比較しているため、これらは誤りです(ありがとう Niall )。

0 == '' // true

したがって、0falsyであり、空の文字列がfalsyであるため、これが真である理由。

0 == '0' // true

これは少しトリッキーです。仕様では、オペランドが文字列と数値の場合、文字列を数値に強制変換すると規定されています。 '0'0になります。ありがとう smfoote

false == undefined // false

undefinedはJavaScriptで特別であり、null以外の値と同じではありません。ただし、偽りです。

false == null // false

繰り返しますが、nullは特別です。 undefinedと等しいだけです。また、偽りです。

null == undefined // true

nullundefinedは似ていますが、同じではありません。 nullnothingを意味し、undefinedは設定されていないか存在しない変数の値です。それらの値が等しいと見なされることは、ある意味で理にかなっています。

本当に混乱したい場合は、これを確認してください...

'\n\r\t' == 0

空白のみで構成される文字列は、0に等しいと見なされます。

ダグラス・クロックフォードはたくさんの推薦をします、しかしあなたはそれらを福音としてとらえる必要はありません。 :)

T.J。Crowder これらの同等性テストの背後にある全体像を知るために ECMAScript言語仕様 を研究することを提案します。

参考文献?

仕様

yolpo(偽の値)

30
alex

この質問への答えは、JavaScriptが強制を処理する方法と関係があります。 _==_の場合、 文字列は強制的に数値になります 。したがって:

_'' == '0'_は_'' === '0'_と同等です(どちらも文字列であるため、強制は必要ありません)。

_0 == ''_は_0 === 0_と同等です。これは、文字列_''_が数値_0_(math.abs('') === 0)になるためです。

_0 == '0'_は、同じ理由で_0 === 0_と同等です。

_false == undefined_は_0 === undefined_と同等です。これは、タイプが一致しない場合、JavaScriptがブール値を数値に強制変換するためです。

_false == null_は、同じ理由で_0 === null_と同等です。

仕様にそのように記載されているため、_null == undefined_はtrueです。

この質問をしてくれてありがとう。 _==_についての私の理解は、それを研究したことではるかに良くなりました。

8
smfoote

実際には、==とまったく同じように動作するJavaScript関数を記述して、その動作についての洞察を得ることができます。

ここで私が意味することを示すために、その関数は次のとおりです。

// loseEqual() behaves just like `==`
function loseEqual(x, y) {
    // notice the function only uses "strict" operators 
    // like `===` and `!==` to do comparisons

    if(typeof y === typeof x) return y === x;

    if(typeof y === "function" || typeof x === "function") return false;

    // treat null and undefined the same
    var xIsNothing = (y === undefined) || (y === null);
    var yIsNothing = (x === undefined) || (x === null);

    if(xIsNothing || yIsNothing) return (xIsNothing && yIsNothing);

    if(typeof x === "object") x = toPrimitive(x);
    if(typeof y === "object") y = toPrimitive(y);

    if(typeof y === typeof x) return y === x;

    // convert x and y into numbers if they are not already use the "+" trick
    if(typeof x !== "number") x = +x;
    if(typeof y !== "number") y = +y;

    return x === y;
}

function toPrimitive(obj) {
    var value = obj.valueOf();
    if(obj !== value) return value;
    return obj.toString();
}

ご覧のとおり、==には型変換のための複雑なロジックがたくさんあります。そのため、どのような結果が得られるかを予測するのは困難です。

予期しない結果の例を次に示します。

予期しない真実

[1] == true // returns true
'0' == false // returns true
[] == false // returns true
[[]] == false // returns true
[0] == false // returns true

'\r\n\t' == 0 // returns true

予期しない結論

// IF an empty string '' is equal to the number zero (0)
'' == 0 // return true

// AND the string zero '0' is equal to the number zero (0)
'0' == 0 // return true

// THEN an empty string must be equal to the string zero '0'
'' == '0' // returns **FALSE**

特殊機能を持つオブジェクト

// Below are examples of objects that
// implement `valueOf()` and `toString()`

var objTest = {
    toString: function() {
        return "test";
    }
};

var obj100 = {
    valueOf: function() {
        return 100;
    }
};

var objTest100 = {
    toString: function() {
        return "test";
    },
    valueOf: function() {
        return 100;
    }
};

objTest == "test" // returns true
obj100 == 100 // returns true
objTest100 == 100 // returns true

objTest100 == "test" // returns **FALSE**
4
Luis Perez