ここでの条件が true と評価されるのはなぜでしょうか?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
ここでの条件が true と評価されるのはなぜでしょうか?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
それを分解してください:
var condition = new Boolean(false);
これは実際にはオブジェクトであり、condition.valueOf() === false
!{}
true であるため、false と評価されます ( http://www.ecma-international.org/ecma-262/5.1/#sec-9.2{}
で説明されています) 。
したがって、チェックは ですcondition.valueOf() == false
。これは true です
false
オブジェクト (LHS) をブール値(RHS)と比較しています。
[object Boolean] == false
オペレーターは、ECMAScript で定義された抽象等価比較アルゴリズム==
に従って型強制を実行します。11.9.3 抽象等価比較アルゴリズム
コードに関連するのは、そのアルゴリズムの次のポイントです(x は LHS、y は RHS です)。
7) Type(y) が Boolean の場合、比較 x == ToNumber(y) の結果を返します。
実際には最初にブール値を数値に変換しようとすることに注意してください。false
ブール値は数値に変換されるため、次の0
ようになります。
[object Boolean] == 0
ご覧のとおり、==
. オブジェクトを数値と比較しているので、次の点が当てはまります。
9) Type(x) が Object で、Type(y) が String または Number の場合、比較 ToPrimitive(x) == y の結果を返します。
ここでは、オブジェクトをプリミティブ値に強制しようとしています。9.1 ToPrimitiveから、オブジェクトで呼び出された場合:
Object オブジェクト のデフォルト値を返します。オブジェクトのデフォルト値は、オブジェクトの [[DefaultValue]] 内部メソッドを呼び出し、オプションのヒント PreferredType を渡すことによって取得されます。[[DefaultValue]] 内部メソッドの動作は、8.12.8 のすべてのネイティブ ECMAScript オブジェクトについて、この仕様によって定義されています。
オブジェクトの が必要であることがわかり[[DefaultValue]]
ます。これで8.12.8 [[DefaultValue]]にたどり着き、そこで「ヒント」が期待されます。「ヒント」を受け取っていないため、ヒントが「数値」であるかのように動作します。
O の [[DefaultValue]] 内部メソッドがヒントなしで呼び出されると、ヒントが Number であるかのように動作します...
そのため、次の動作が発生します。
O の [[DefaultValue]] 内部メソッドがヒント Number で呼び出されると、次の手順が実行されます。
valueOf をオブジェクト O の [[Get]] 内部メソッドを引数「valueOf」で呼び出した結果とする。
IsCallable(valueOf) が true の場合、
を。val を valueOf の [[Call]] 内部メソッドを呼び出した結果とし、O を this 値とし、引数リストを空にします。
b. val がプリミティブ値の場合、val を返します。
.valueOf()
オブジェクトのメソッドを呼び出して、15.6.4.3 Boolean.prototype.valueOf ( )に移動します。
B を this の値とします。
Type(B) が Boolean の場合、b を B とします。
それ以外の場合、Type(B) が Object で、B の [[Class]] 内部プロパティの値が "Boolean" の場合、b を B の [[PrimitiveValue]] 内部プロパティの値とします。
それ以外の場合は、TypeError 例外をスローします。
b を返します。
したがって、ステップ 3 から、オブジェクトの が返されることがわかり[[PrimitiveValue]]
ます。これにより、15.6.2.1 new Boolean (value)が表示されます
新しく構築された Boolean オブジェクトの [[PrimitiveValue]] 内部プロパティは ToBoolean(value) に設定されます。
ToBoolean
そして、コンストラクターに最初に渡した値の値を最終的に取得することがわかりますfalse
。そのToBoolean
値は明らかにfalse
であるため、比較は次のようになります。
false == 0
タイプがまだ一致しないため、元のアルゴリズムのポイント 6 に進みます。
6) Type(x) が Boolean の場合、比較 ToNumber(x) == y の結果を返します。
そのため、ブール値false
を数値に変換する必要があります。これは、上記で行ったことと同様です。valueは value にfalse
変換されるため、次の0
ようになります。
0 == 0
最後に、型が一致した比較があるため、値を比較することにより、厳密な対応と同じように動作===
します。そして明らかに、0
は等しい0
ので、 が得られtrue
ます。
話の教訓... これは、JavaScript で「なぜ」と尋ねると得られるものです。
これが論理的にレイアウトされている仕様を読むだけで本当に役に立ちます。
皮切りに:
var x = new Boolean(false);
var y = !x;
それで
y = false;
ブール値オブジェクトはブール値ではなく日常的なオブジェクトと見なされるため、 にToBoolean(x)
評価されtrue
、 は に!true
評価されますfalse
ラウンド 1: ステップ 7
Type(y) が Boolean の場合、比較 x == ToNumber(y) の結果を返します。
y = 0; //ToNumber(false) is 0
ラウンド 2: ステップ 9
Type(x) が Object で Type(y) が String または Number の場合、比較 ToPrimitive(x) == y の結果を返します。
x = false //Basically ends up calling x.valueOf()
ラウンド 3:ステップ 6
Type(x) が Boolean の場合、比較 ToNumber(x) == y の結果を返します。
x = 0; //ToNumber(false) is 0
最後に:ステップ 1
Type(x) が Type(y) と同じ場合、
ステップ 1 C
Type(x) が Number の場合、
ステップ 1 C iii
x が y と同じ数値の場合、true を返します。
The Abstract Equality Comparison Algorithmから学んだことの 1 つは、直感を忘れて手順に従うことです。
オブジェクトが真であるため、それらの否定は ですfalse
。したがって、アルゴリズムに入る内容は次のとおりです。
Boolean(false) == false
一歩一歩進むと、次のようになります。
Boolean(false) == 0 // Step 7
false == 0 // Step 9
0 == 0 // Step 6
true