JavaScript trick: a == 1 && a == 2 && a == 3

Vediamo come sfruttare le potenziali di JavaScript per verificare una condizione inverificabile.

Introduzione

JavaScript è un linguaggio di programmazione diverso da ogni altro linguaggio esistente. Nonostante sia un linguaggio all'apparenza strano ed illogico, in realtà è molto intelligente e potente. L'utilizzo abituale lo rende sempre più semplice ed efficace.

L'operatore ==

A differenza degli altri linguaggi di programmazione, l'operatore == in JavaScript (loose equality) permette di confrontare due operandi eseguendo, innanzitutto, una conversione di entrambi i valori in un tipo comune e solo successivamente verificando la condizione. Questo è il motivo per il quale la seguente condizione risulta vera:

if ("1" == 1)
    console.log("Condizione valida");
else
    console.log("Condizione non valida");

Condizione valida

Ciò che succede effettivamente è che quando l'if viene valutato, su entrambi gli operatori viene chiamato il metodo toString() che quindi corrisponde a scrivere il codice nel seguente modo:

if ("1".toString() == 1.toString())

Di conseguenza la condizione valutata è la seguente:

if ("1" == "1")

Per questo motivo la condizione risulta vera nonostante i due valori confrontati hanno tipi diversi. Nel caso in cui invece volessimo garantire un controllo anche sul tipo dei valori allora si renderebbe necessario l'utilizzo dell'operatore === chiamato strict equality. Questo operatore è più simile agli operatori di uguaglianza esistenti nei classici linguaggi.

if ("1" === 1)
    console.log("Condizione valida");
else
    console.log("Condizione non valida");

Condizione non valida

Come verificare una condizione inverificabile

A questo punto abbiamo tutti gli strumenti per poter verificare una condizione che non risulterebbe valida in nessun altro linguaggio.

if (a == 1 && a == 2 && a == 3)
    console.log("Condizione valida");
else
    console.log("Condizione non valida");

Condizione valida

Per poter garantire ciò dobbiamo fare in modo che la variabile presa in considerazione valga 1, 2, 3 contemporaneamente o quasi e per farlo possiamo andare a sovrascrivere il metodo toString() di un oggetto. Iniziamo quindi creando un oggetto che abbia una proprietà inizializzata ad 1.

let a = {
    value: 1
}

Fatto ciò andiamo a sovrascrivere il metodo toString() dell'oggetto che ritornerà il valore della proprietà value con post incremento.

let a = {
    value: 1,
    toString: function() {
        return this.value++;
    }
}

Ad ogni chiamata del metodo toString() verrà ritornato il valore della proprietà value che successivamente verrà incrementata di 1. Sarebbe comunque possibile utilizzare il pre incremento invece del post inizializzando il valore della proprietà value a 0.

let a = {
    value: 0,
    toString: function() {
        return ++this.value;
    }
}

La logica è completa ed ora non ci resta che andare a verificare la condizione.

if (a == 1 && a == 2 && a == 3)

La condizione riportata in realtà viene interpretata nel seguente modo:

if (a.toString() == 1.toString() && a.toString() == 2.toString() && a.toString() == 3.toString())

Alla prima chiamata del metodo toString() sull'oggetto a il valore ritornato sarà 1 e poi questo valore sarà incrementato. Lo stesso processo verrà ripetuto per ogni ulteriore uguaglianza. Potremmo avere lo stesso risultato andando direttamente ad incrementare una variabile numerica semplice:

let a = 1;

if (a++ == 1 && a++ == 2 && a++ == 3)
    console.log("Condizione valida");
else
    console.log("Condizione non valida");

Condizione valida

Conclusioni

Inizialmente lavorare con JavaScript è molto frustrante perché, nonostante il codice possa essere molto simile ad altri linguaggi di programmazione, potrebbe non avere lo stesso comportamento. Con il tempo (e molto StackOverflow) JavaScript potrebbe diventare anche divertente da utilizzare e soprattutto molto interessante anche da un punto di vista lavorativo, essendo il linguaggio più utilizzato al mondo.