8

重複の可能性:
空の JavaScript 配列のブール値の競合

という事実の背後にある理論的根拠は何ですか

[ ([] == false), ([] ? 1 : 2) ]

を返します[true, 1]か?

言い換えると、空のリストはブール値のコンテキストでは論理的に true ですが、 と等しくなりfalseます。

を使用することで問題が解決することはわかって===いますが、この明らかに完全に非論理的な選択の背後にある説明は何ですか?

言い換えれば、これは言語の間違いであると考えられています。意図せずに起こった何かであり、手遅れであるために修正することはできません。または、言語の設計上、誰かがこの種の明らかな狂気を持っていることをクールだと考えていました。確かに、多くのプログラマーにとってかなり混乱していますか?

これがどのように起こるかの技術的な説明は驚くべきと同時に恐ろしいものですが、私はこのデザインの背後にあるものにもっと興味がありました.

編集

私は非常に詳細な Nick Retallack の説明を受け入れましたが、それが真である理由の技術的な理由についてのみでした[]==false: 驚くべきこと[]に、文字列に変換されたものが空の文字列であり、空の文字列の数値が明らかにではなく 0 になるように特別にケース化されているためです。より論理的NaN。たとえば、空のオブジェクトの場合、空のオブジェクト({}) == falseの文字列表現は空の文字列ではないため、比較は false を返します。

私の好奇心は、これらすべてが予期せぬものであることにまだ残っています(そして、残念ながら標準で固まっています)。

4

2 に答える 2

9

ここでの混乱は、(一般的な考えに反して) と同じではない JavaScript の「偽」の定義に関するもの== falseです。

Falsy は実際には false に相当するブール値を持つ値を指し、結果 == false の式ではありません。JavaScript の Falsy 値はfalse0""nullundefined、およびのみNaNです。したがって、これらの値のいずれか、またはそれらの値のいずれかに評価される式 (ステートメントif内または三項演算子の使用など) は偽です。

これは、この問題全体を説明するのに役立つ JavaScript の偽/真実の値をまとめた表です。 http://jsfiddle.net/philipwalton/QjSYG/

于 2012-05-11T17:32:47.060 に答える
8

技術的な話をしましょう。ECMAScript Standard 262から引用してロジックを説明します。

[] ? 1 : 2は非常に単純です。

11.12 条件演算子 ( ? : )

  • lref を LogicalOREExpression の評価結果とします。
  • ToBoolean (GetValue(lref))が true の場合、
    • 最初の AssignmentExpression を評価した結果を trueRef とします。
    • GetValue(trueRef) を返します。
  • そうしないと
    • 2 番目の AssignmentExpression を評価した結果を falseRef とします。
    • GetValue(falseRef) を返す

9.2 ToBoolean

  • 未定義: false
  • ヌル: false
  • ブール値: 結果は入力引数と等しくなります (変換なし)。
  • Number: 引数が +0、-0、または NaN の場合、結果は false です。それ以外の場合、結果は true です。
  • 文字列: 引数が空の文字列 (長さがゼロ) の場合、結果は false です。それ以外の場合、結果は true です。
  • オブジェクト: 真

それは本当です。


次に、二重等号演算子を使用したときに何が起こるかを見てみましょう。おそらくこれは、これを行うべきではない理由を説明するのに役立ちます。

== の動作は、セクション 11.9.3: 抽象等価比較アルゴリズムで説明されています。

x == y の場合、x = [] および y = false の場合、次のようになります。

11.9.3: 抽象等価比較アルゴリズム

Type(y) が Boolean の場合、比較の結果を返します x == ToNumber(y)

9.3 ToNumber

引数が falseの場合、結果は+0です。

[] == 0

11.9.3: 抽象等価比較アルゴリズム

Type(x) が Object で Type(y) が String または Number の場合、比較ToPrimitive(x) == yの結果を返します。

9.1 プリミティブへ

オブジェクトのデフォルト値を返します。オブジェクトのデフォルト値は、オブジェクトの[[DefaultValue]] 内部メソッドを呼び出し、オプションのヒント PreferredType を渡すことによって取得されます。[[DefaultValue]] 内部メソッドの動作は、8.12.8 のすべてのネイティブ ECMAScript オブジェクトについて、この仕様によって定義されています。

8.12.8 デフォルト値:

O の [[DefaultValue]] 内部メソッドがヒントなしで呼び出されると、ヒントがNumberであるかのように動作します。

  • valueOf をオブジェクト O の [[Get]] 内部メソッドを引数「valueOf」で呼び出した結果とする。
  • IsCallable(valueOf) が true の場合、
    • val を valueOf の [[Call]] 内部メソッドを呼び出した結果とし、O を this 値とし、引数リストを空にします。
    • val がプリミティブ値の場合、val を返します
  • オブジェクト O の [[Get]] 内部メソッドを引数 "toString" で呼び出した結果を toString とする。
  • IsCallable(toString) が true の場合、
    • str をtoStringの [[Call]] 内部メソッドを呼び出した結果とし、 O を this 値とし、引数リストを空にします。
    • str がプリミティブ値の場合、str を返します

結果は最初に使用したのと同じ配列であるため、これは最初に valueOf を試みてから拒否すると思います。次に、配列の toString を呼び出します。これは、その値のコンマ区切りリストとして普遍的に実装されているようです。このような空の配列の場合、空の文字列になります。

これで '' == 0 になりました

11.9.3: 抽象等価比較アルゴリズム

Type(x) が String で Type(y) が Number の場合、比較の結果を返すToNumber(x) == y

9.3.1 文字列型に適用される ToNumber

空であるか空白のみを含むStringNumericLiteral は+0に変換されます。

これで 0 == 0 になりました

11.9.3: 抽象等価比較アルゴリズム

x が y と同じ Number 値の場合、true を返します

素晴らしい。それは本当です。ただし、ここにたどり着くにはかなり複雑な方法です。

于 2012-05-11T17:32:55.793 に答える