Moderator note: コードを編集したり、この通知を削除したいという衝動を抑えてください。空白のパターンは問題の一部である可能性があるため、不必要に手を加えるべきではありません。もしあなたが "whitespace is insignificant" 派であれば、このコードをそのまま受け入れることができるはずです。
JavaScriptで (a== 1 && a ==2 && a==3)
が true
と評価されることはあり得ますか?
これは、ある大手ハイテク企業で行われたインタビューの質問です。2週間前の出来事ですが、いまだに答えを見つけられずにいます。普段の仕事ではそのようなコードを書くことはないと思いますが、気になって仕方がありません。
how==works](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using)を利用すれば、単純にカスタムの
toString(または
valueOf`)関数を持つオブジェクトを作成し、それが使用されるたびに、3つの条件を満たすように返すものを変更することができます。
const a = {
i: 1,
toString: function () {
return a.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('Hello World!');
}
<! -- スニペットの終了 -->
これがうまくいくのは、緩い等号演算子を使用しているからです。緩い等号を使用すると、オペランドの一方が他方と異なる型である場合、エンジンは一方を他方に変換しようとします。左側がオブジェクト、右側が数値の場合、まず valueOf
が呼び出し可能であればそれを呼び出し、それができなければ toString
を呼び出して、オブジェクトを数値に変換しようとします。このケースで toString
を使用したのは、単にそれが頭に浮かんだからで、valueOf
の方がより意味があるでしょう。代わりに toString
から文字列を返した場合、エンジンはその文字列を数値に変換しようとしたでしょうから、最終的な結果は同じになりますが、経路は少し長くなります。
It is possible!
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a == 1 && a == 2 && a == 3)
console.log("wohoo");
}
<! -- スニペットの終了 -->
これは、with
文の中のゲッターを使って、a
が3つの異なる値に評価されるようにしています。
...といっても、これを実際のコードで使うべきだということにはなりませんが...。
さらに悪いことに、このトリックは ===
を使っても機能します。
var i = 0;
with({
get a() {
return ++i;
}
}) {
if (a !== a)
console.log("yep, this is printed.");
}
<! -- スニペットの終了 -->
これは、グローバルスコープで以下のようにして実現できます。nodejsでは、以下のコードで
windowの代わりに
global`を使用します。
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('yay');
}
<! -- スニペットの終了 -->
この回答は、変数を取得するゲッターを定義することで、実行コンテキストのグローバルスコープが提供する暗黙の変数を悪用しています。