Kan (a== 1 && a ==2 && a==3) någonsin utvärderas till sant?

Anmärkning från moderatorn: Motstå inte lusten att redigera koden eller ta bort det här meddelandet. Mönstret med vitrymder kan vara en del av frågan och bör därför inte manipuleras i onödan. Om du tillhör lägret "whitespace is insignificant" bör du kunna acceptera koden som den är.

Är det någonsin möjligt att (a== 1 && a ==2 && a==3) kan utvärderas till true i JavaScript?

Detta är en intervjufråga som ställdes av ett stort teknikföretag. Det hände för två veckor sedan, men jag försöker fortfarande hitta svaret. Jag vet att vi aldrig skriver sådan kod i vårt dagliga arbete, men jag är nyfiken.

Lösning

Om du drar nytta av [how == works] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#Loose_equality_using) kan du helt enkelt skapa ett objekt med en anpassad funktion toString (eller valueOf) som ändrar vad den returnerar varje gång den används så att den uppfyller alla tre villkoren.

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

Anledningen till att detta fungerar är att vi använder den lösa likhetsoperatorn. Om en av operanderna är av en annan typ än den andra, försöker motorn konvertera den ena till den andra. I fallet med ett objekt till vänster och ett nummer till höger försöker den konvertera objektet till ett nummer genom att först anropa valueOf om den kan anropas, och om det inte går, anropar den toString. Jag använde toString i det här fallet helt enkelt för att det var det som jag kom att tänka på, valueOf skulle vara mer meningsfullt. Om jag i stället hade returnerat en sträng från toString skulle motorn sedan ha försökt konvertera strängen till ett tal, vilket skulle ha gett oss samma slutresultat, men med en något längre väg.

Kommentarer (19)

DET ÄR MÖJLIGT!

var i = 0;

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

Här används en getter inuti ett with-meddelande för att låta a utvärderas till tre olika värden.

... detta betyder fortfarande inte att detta bör användas i riktig kod...

Ännu värre är att det här tricket också fungerar med hjälp av ===.

  var i = 0;

  with({
    get a() {
      return ++i;
    }
  }) {
    if (a !== a)
      console.log("yep, this is printed.");
  }
Kommentarer (12)

Det kan göras genom att använda följande i det globala området. För nodejs använd global istället för window i koden nedan.

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

Det här svaret missbrukar de implicita variabler som tillhandahålls av det globala tillämpningsområdet i exekveringskontexten genom att definiera en getter för att hämta variabeln.

Kommentarer (6)