Може ли (a== 1 && a ==2 && a==3) някога да се оцени като true?

Забележка на модератора: Моля, не се поддавайте на желанието да редактирате кода или да премахнете това съобщение. Моделът на белите полета може да е част от въпроса и затова не трябва да се променя излишно. Ако сте в лагера на "белите полета са незначителни", би трябвало да можете да приемете кода в този му вид.

Възможно ли е някога (a== 1 && a ==2 && a==3) да се оцени като true в JavaScript?

Това е въпрос от интервю, зададен от голяма технологична компания. Това се случи преди две седмици, но все още се опитвам да намеря отговора. Знам, че никога не пишем такъв код в ежедневната си работа, но съм любопитен.

Решение

Ако се възползвате от как работи ==, можете просто да създадете обект с персонализирана функция toString (или valueOf), която да променя това, което връща всеки път, когато се използва, така че да удовлетворява и трите условия.

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, двигателят щеше да се опита да преобразува низа в число, което щеше да ни даде същия краен резултат, макар и с малко по-дълъг път.

Коментари (19)

ВЪЗМОЖНО Е!

var i = 0;

with({
  get a() {
    return ++i;
  }
}) {
  if (a == 1 && a == 2 && a == 3)
    console.log("wohoo");
}

Това използва getter в оператора with, за да позволи на a да се оцени на три различни стойности.

... това все още не означава, че трябва да се използва в реален код...

Още по-лошо е, че този трик ще работи и при използването на ===.

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }
Коментари (12)

Това може да се осъществи чрез следното в глобалния обхват. За nodejs използвайте global вместо window в кода по-долу.

var val = 0;
Object.defineProperty(window, 'a', {
  get: function() {
    return ++val;
  }
});
if (a == 1 && a == 2 && a == 3) {
  console.log('yay');
}

Този отговор злоупотребява с имплицитните променливи, предоставени от глобалния обхват в контекста на изпълнение, като дефинира getter за извличане на променливата.

Коментари (6)