(a==1 && a==2 && a==3)
true
返すことができ
true
か?」でした。 質問に対する答えは、奇妙なことに、肯定的でした。
今日は、このコードを分析し、理解しようとします。
ここにあります:
const a = { num: 0, valueOf: function() { return this.num += 1 } }; const equality = (a==1 && a==2 && a==3); console.log(equality); // true
Google Chromeを使用している場合、Windowsではキーボードショートカット
Ctrl + Shift + J
Cmd + Opt + J
、macOSでは
Cmd + Opt + J
を使用して開発者ツールコンソールを開きます。 このコードをコピーし、コンソールに貼り付けて、出力が
true
であることを確認し
true
。
キャッチは何ですか?
実際、ここでは驚くべきことは何もありません。 このコードは、単純に2つの基本的なJavaScriptの概念を使用しています。
- 緩やかな平等の演算子。
-
valueOf()
オブジェクトのメソッド。
厳密な等価演算子
検討中の式
(a==1 && a==2 && a==3)
では、非厳密な等価演算子が使用されていることに注意してください。 つまり、この式の値の計算中に、タイプ変換が使用されます。つまり、
==
を使用すると、異なるタイプの値を比較できます。 これについてはすでにたくさん書いたので、ここでは詳しく説明しません。 JSの比較演算子の機能を思い出す必要がある場合は、 この資料を参照してください。
ValueOf()メソッド
JavaScriptには、オブジェクトをプリミティブ値に変換するための組み込みメソッド
Object.prototype.valueOf()
ます。 デフォルトでは、このメソッドは呼び出されたオブジェクトを返します。
オブジェクトを作成します。
const a = { num: 0 }
上記のように、オブジェクト
a
で
valueOf()
を呼び出すと、単にオブジェクト自体が返されます。
a.valueOf(); // {num: 0}
さらに、
typeOf()
を使用して、
valueOf()
実際にオブジェクトを返すかどうかを確認できます。
typeof a.valueOf(); // "object"
valueOf()を記述します
valueOf()
使用する際の最も興味深いことは、オブジェクトをプリミティブ値に変換するためにこのメソッドをオーバーライドできることです。 つまり、
valueOf()
を使用して、オブジェクトの代わりに文字列、数値、ブール値などを返すことができます。 次のコードを見てください。
a.valueOf = function() { return this.num; }
ここで、オブジェクト
a
標準の
valueOf()
メソッドを置き換えまし
a
。 現在、
valueOf()
呼び出すと、値
a.num
ます。
これはすべて次のことにつながります。
a.valueOf(); // 0
ご覧のとおり、
valueOf()
は0を返します! ここで最も重要なことは、0が
a.num
オブジェクトのプロパティに割り当てられる値であることです。 これを検証するには、いくつかのテストを実行します。
typeof a.valueOf(); // "number" a.num == a.valueOf() // true
次に、これが重要である理由について説明しましょう。
非厳密な等価操作と型キャスト
さまざまなタイプのオペランドの非厳密な等値演算の結果を計算するとき、JavaScriptはタイプをキャストしようとします。つまり、オペランドを同様のタイプまたは同じタイプにキャスト(変換)しようとします。
式
(a==1 && a==2 && a==3)
では、JavaScriptはオブジェクト
a
を数値と比較する前に数値型にキャストしようとします。 JavaScriptオブジェクトでキャスト操作を実行する場合、最初に
valueOf()
メソッドを呼び出そうとします。
標準の
valueOf()
メソッドを変更して、数値
a.num
返すようになったため、次のことができるようになりました。
a == 0 // true
問題は解決しましたか? まだではありませんが、何も残っていません。
追加の割り当て演算子
ここで、
valueOf()
呼び出されるたびに体系的に
a.num
の値を増やす方法が必要です。 幸いなことに、JavaScriptには、追加の代入演算子または追加の代入演算子(
+=
)があります。
この演算子は、右側のオペランドの値を左側の変数に追加し、結果の値をこの変数に割り当てます。 以下に簡単な例を示します。
let b = 1 console.log(b+=1); // 2 console.log(b+=1); // 3 console.log(b+=1); // 4
ご覧のとおり、追加で代入演算子を使用するたびに、変数の値が増加します!
valueOf()
メソッドでこのアイデアを使用します。
a.valueOf = function() { return this.num += 1; }
valueOf()
呼び出すたびに
this.num
返す代わりに、
this.num
の値を1増やして返し、新しい値を
this.num
ます。
コードにこの変更を加えた後、最終的にすべてを試すことができます。
const equality = (a==1 && a==2 && a==3); console.log(equality); // true
うまくいく!
段階的な分析
緩やかな等価演算子を使用する場合、JSは型変換を実行しようとすることに注意してください。 このオブジェクトは、
a.num += 1
を返す
valueOf()
メソッドを呼び出します。つまり、呼び出されるたびに1ずつ増加した
a.num
の値を返します。 今では2つの数値を比較するだけです。 この場合、すべての比較で
true
が生成され
true
。
何が起こっているのかを段階的に検討することが役立つ場合があります。
a == 1 -> a.valueOf() == 1 -> a.num += 1 == 1 -> 0 += 1 == 1 -> 1 == 1 -> true a == 2 -> a.valueOf() == 2 -> a.num += 1 == 2 -> 1 += 1 == 2 -> 2 == 2 -> true a == 3 -> a.valueOf() == 3 -> a.num += 1 == 3 -> 2 += 1 == 3 -> 3 == 3 -> true
まとめ
上記のような例は、まずJavaScriptの基本的な機能をよりよく理解するのに役立つと信じています。次に、JSですべてが見た目ではないことを忘れないでください。
親愛なる読者! JavaScriptの分野の奇妙な点を知っている場合は、それらを共有してください。