コンストラクト(a == 1 && a == 2 && a == 3)はJavaScriptでtrueにできますか?

最近、JavaScriptコードの興味深い部分がTwitterReddit上を歩きまし 。 それに関する質問は、「式(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の概念を使用しています。


厳密な等価演算子


検討中の式(a==1 && a==2 && a==3)では、非厳密な等価演算子が使用されていることに注意してください。 つまり、この式の値の計算中に、タイプ変換が使用されます。つまり、 ==を使用すると、異なるタイプの値を比較できます。 これについてはすでにたくさん書いたので、ここでは詳しく説明しません。 JSの比較演算子の機能を思い出す必要がある場合は、 この資料を参照しください。

ValueOf()メソッド


JavaScriptには、オブジェクトをプリミティブ値に変換するための組み込みメソッドObject.prototype.valueOf()ます。 デフォルトでは、このメソッドは呼び出されたオブジェクトを返します。

オブジェクトを作成します。

 const a = { num: 0 } 

上記のように、オブジェクトavalueOf()を呼び出すと、単にオブジェクト自体が返されます。

 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の分野の奇妙な点を知っている場合は、それらを共有してください。

Source: https://habr.com/ru/post/J347530/


All Articles