Può (a==1 && a ==2 && a==3) valutare mai come vero?

Nota del moderatore: Si prega di resistere all'impulso di modificare il codice o rimuovere questo avviso. Lo schema degli spazi bianchi può essere parte della questione e quindi non dovrebbe essere manomesso inutilmente. Se siete nel campo "gli spazi bianchi sono insignificanti", dovreste essere in grado di accettare il codice così com'è.

È mai possibile che (a==1 && a ==2 &&a==3) possa valutare a true in JavaScript?

Questa è una domanda di intervista fatta da un'importante azienda tecnologica. È successo due settimane fa, ma sto ancora cercando di trovare la risposta. So che non scriviamo mai tale codice nel nostro lavoro quotidiano, ma sono curioso.

Soluzione

Se si approfitta di come funziona ==, si potrebbe semplicemente creare un oggetto con una funzione personalizzata toString (o valueOf) che cambia ciò che restituisce ogni volta che viene usata in modo da soddisfare tutte e tre le condizioni.

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

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

La ragione per cui questo funziona è dovuta all'uso dell'operatore di uguaglianza sciolta. Quando si usa l'uguaglianza sciolta, se uno degli operandi è di un tipo diverso dall'altro, il motore tenterà di convertire uno nell'altro. Nel caso di un oggetto a sinistra e un numero a destra, tenterà di convertire l'oggetto in un numero chiamando prima valueOf se è richiamabile, e in caso contrario, chiamerà toString. Ho usato toString in questo caso semplicemente perché è quello che mi è venuto in mente, valueOf avrebbe più senso. Se invece avessi restituito una stringa da toString, il motore avrebbe poi tentato di convertire la stringa in un numero dandoci lo stesso risultato finale, anche se con un percorso leggermente più lungo.

Commentari (19)

È POSSIBILE!

var i = 0;

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

Questo usa un getter all'interno di un'istruzione with per permettere ad a di valutare tre diversi valori.

... questo ancora non significa che questo dovrebbe essere usato nel codice reale...

Ancora peggio, questo trucco funzionerà anche con l'uso di ===.

  var i = 0;

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

Può essere realizzato usando quanto segue nell'ambito globale. Per nodejs usate global invece di window nel codice sottostante.

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

Questa risposta abusa delle variabili implicite fornite dall'ambito globale nel contesto di esecuzione definendo un getter per recuperare la variabile.

Commentari (6)