(A == 1 && a == 2 && a == 3) può mai essere considerato vero?


2484

Nota del moderatore: resistere alla tentazione di modificare il codice o rimuovere questo avviso. Lo schema degli spazi bianchi può essere parte della domanda e pertanto non deve essere manomesso inutilmente. Se ti trovi nel campo "spazi bianchi è insignificante", dovresti essere in grado di accettare il codice così com'è.

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

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


9
I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
ingannare

109
Per le persone che apparentemente hanno votato per cloa questo come troppo ampio : è uno scavo su Javascript, dicendo che ci sono troppe risposte valide?
tomsmeding

24
Alcune persone si siedono attorno a filosofare su ciò che è possibile. Altri concentrano i loro sforzi sul fatto che stiano costruendo o meno prodotti fattibili e validi per i loro clienti. IMO, questa domanda non ha alcuna utilità pratica oltre al fatto che non dovresti mai porre questo tipo di domande in un'intervista o scrivere questo tipo di codice. Ecco perché dovrebbe essere chiuso. Voglio dire, l'impresa si rende conto di aver pagato qualcuno con soldi veri per sedersi e parlare di queste cose?
P.Brian.Mackey,

15
Dopo aver letto le risposte, la morale della storia è: non usare ==quando intendi ===, avere uno standard di codifica che vieta i nomi di variabili non ASCII e ha un processo di linting che impone le due morali precedenti.
Jesse C. Slicer,

87
Nota del moderatore: Stack Overflow ha avuto una storia di persone che rispondevano con risposte in diverse lingue a quella in questione. Questi sono tentativi di rispondere alla domanda perché sono soluzioni al problema generale, sebbene in una lingua diversa. Si prega di astenersi dal contrassegnarli come "non una risposta". Detto questo, si prega di astenersi dal pubblicare più risposte in diverse lingue - c'è una ragione per cui questa domanda è specifica per JavaScript, come sottolineato dai commenti sotto alcune di queste altre risposte, e c'è una ragione per cui ci piacciono le nostre domande specifiche sulla lingua rimanere così.
BoltClock

Risposte:


3323

Se approfitti di come ==funziona , potresti semplicemente creare un oggetto con una funzione personalizzata toString(o valueOf) che cambia ciò che restituisce ogni volta che viene utilizzato in modo tale 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!');
}


Il motivo per cui funziona è dovuto all'uso dell'operatore di uguaglianza libera. Quando si utilizza l'uguaglianza libera, se uno degli operandi è di tipo diverso dall'altro, il motore tenterà di convertire l'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 valueOfse è richiamabile e, in caso contrario, chiamerà toString. Ho usato toStringin questo caso semplicemente perché è quello che mi è venuto in mente, valueOfavrebbe più senso. Se invece avessi restituito una stringa da toString, il motore avrebbe quindi tentato di convertire la stringa in un numero dandoci lo stesso risultato finale, sebbene con un percorso leggermente più lungo.


70
Potresti raggiungere questo obiettivo modificando l' valueOf()operazione implicita ?
Sterling Archer,

43
Sì, valueOf funziona al posto di toString per lo stesso motivo
Kevin B,

4
I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
ingannare

13
In base a ciò verrà tentata prima una conversione numerica, quindi valueOfè leggermente migliore.
Salman A

6
@Pureferret il lato sinistro del confronto di uguaglianza è un oggetto, non un numero. Che quell'oggetto abbia una proprietà numerica attiva inon disturba il motore. ;)
tomsmeding il

2057

Non ho potuto resistere: le altre risposte sono senza dubbio vere, ma non puoi davvero superare il seguente codice:

var a = 1;
var a = 2;
var a = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    console.log("Why hello there!")
}

Nota la strana spaziatura ifnell'affermazione (che ho copiato dalla tua domanda). È l'Hangul a mezza larghezza (che è coreano per coloro che non hanno familiarità) che è un carattere spaziale Unicode che non è interpretato dallo script ECMA come un carattere spaziale - ciò significa che è un carattere valido per un identificatore. Pertanto ci sono tre variabili completamente diverse, una con l'Hangul dopo la a, una con essa prima e l'ultima con solo a. Sostituendo lo spazio con _per leggibilità, lo stesso codice sarebbe simile al seguente:

var a_ = 1;
var a = 2;
var _a = 3;
if(a_==1 && a== 2 &&_a==3) {
    console.log("Why hello there!")
}

Controlla la convalida sul validatore del nome variabile di Mathias . Se quella strana spaziatura fosse effettivamente inclusa nella loro domanda, sono sicuro che sia un suggerimento per questo tipo di risposta.

Non farlo Sul serio.

Modifica: Mi è venuto in mente che (sebbene non sia consentito avviare una variabile) i caratteri joiner a larghezza zero e caratteri non-joiner a larghezza zero sono consentiti anche nei nomi delle variabili - vedi Offuscamento JavaScript con caratteri a larghezza zero - pro e contro ?.

Questo sarebbe simile al seguente:

var a= 1;
var a‍= 2; //one zero-width character
var a‍‍= 3; //two zero-width characters (or you can use the other one)
if(a==1&&a‍==2&&a‍‍==3) {
    console.log("Why hello there!")
}


368
A giudicare dalla strana spaziatura della domanda originale, penso che questa sia ESATTAMENTE la risposta che la domanda dell'intervista stava cercando, sfruttando personaggi non spaziali che sembrano spazi. Buon posto!
Baracus il

18
@Baracus È stato RonJohn a notare la strana spaziatura nel suo commento sulla risposta di Kevin che mi ha ricordato questa (terribile) tecnica, quindi non posso prendermi il merito di averla individuata. Ero un po 'sorpreso che nessuno avesse già risposto con questo, dato che è andato in giro per il mio lavoro qualche anno fa a causa di un post sul blog da qualche parte - immaginavo che ormai fosse una conoscenza abbastanza comune.
Jeff,

102
Naturalmente, questo è vietato come scappatoia standard , che si applica anche alle interviste. [citazione necessaria]
Sanchises

13
Considerando la spaziatura originale, potrebbe essere anche peggio, cioè var ᅠ2 = 3è stata usata una variabile ; quindi ci sono le tre variabili aᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3, quindi (a␣==1 && a==␣2 && a==3)) ...
Holger,

2
@ AL-zami c'è un carattere in più in due delle variabili, che mostra sullo schermo come uno spazio, ma viene interpretato come parte dell'identificatore, nel senso che ci sono tre variabili separate - a, a e a - il carattere in più è lo spazio a metà larghezza dell'Hangul.
Jeff

620

È POSSIBILE!

var i = 0;

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

Questo utilizza un getter all'interno di withun'istruzione per lasciarea valutare tre diversi valori.

... questo non significa ancora che 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.");
  }


65
Sì, stavo provando la stessa cosa :) Quindi la risposta corretta nell'intervista sarebbe "Non può accadere nel mio codice perché non lo uso mai with".
Puntato il

7
@Pointy - E, programma in modalità rigorosa dove withnon è consentito.
jfriend00,

6
@Pointy nella risposta accettata fanno qualcosa di simile senza che withciò possa accadere
Jungkook

2
@jorrit nessuno userebbe ==. E ===impedisce la risposta accettata
Jonas Wilms,

4
@JonasW. Molte persone usano ancora ==ma non vedo da withallora ... beh in realtà mai al di fuori della documentazione di JS in cui si dice "per favore non usarlo". Comunque, una bella soluzione.
Wortwart,

516

Esempio senza getter o valueOf:

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

Questo funziona perché ==invoca toStringquali chiamate.join array.

Un'altra soluzione, Symbol.toPrimitiveche utilizza un equivalente ES6 di toString/valueOf:

let i = 0;
let a = { [Symbol.toPrimitive]: () => ++i };

console.log(a == 1 && a == 2 && a == 3);


9
without valueOf, beh ... è più indiretto ma sostanzialmente la stessa cosa.
Jonas Wilms,

11
Mi piace molto questa soluzione perché non si ignora nulla ma gli oggetti possiedono la funzione join ed è solo un hack molto pulito e di facile lettura che rende la logica valutata vera.
Alex Pedersen,

28
Onestamente penso che questa sia la risposta migliore. Non comporta nulla di straordinario, basta impostare alcuni valori. Molto facile da capire anche con le conoscenze di base di JS. Molto bene.
Zac Delventhal,

14
Questo ha molto senso che sembra quasi utile.
Andrew

7
Sapevo che la maggior parte delle risposte riguardava l'abuso toStringo valueOfma questo mi ha preso completamente alla sprovvista. Molto intelligente e non sapevo che chiamasse .joininternamente, ma ha perfettamente senso.
GBarroso,

268

Se viene chiesto se è possibile (non DEVE), può chiedere a "a" di restituire un numero casuale. Sarebbe vero se genera 1, 2 e 3 in sequenza.

with({
  get a() {
    return Math.floor(Math.random()*4);
  }
}){
  for(var i=0;i<1000;i++){
    if (a == 1 && a == 2 && a == 3){
      console.log("after " + (i+1) + " trials, it becomes true finally!!!");
      break;
    }
  }
}


102
Darei deliberatamente questa risposta anche se conoscessi le altre soluzioni, perché risponde alla domanda ma ovviamente non è quello che stavano cercando. Gioca a stupidi giochi, vinci stupidi premi.
ESR,

2
E se ci volessero più di 1000 prove?
Piyin,

9
@Piyin Se ci vogliono più di 1000 prove, vinci un premio!
Skeets,

5
Mi piace questa risposta perché portarla all'estremo suggerisce che ciò è possibile in qualsiasi lingua se i registri / cache della cpu vengono colpiti con abbastanza raggi cosmici mentre il programma è in esecuzione, o se si esegue deliberatamente un glitch di potenza tale che il ramo di errore di il if condizionale in realtà non salta.
Ponkadoodle,

Più basso: 1, più alto: 412.
KyleFairns

210

Quando non puoi fare nulla senza le espressioni regolari:

var a = {
  r: /\d/g, 
  valueOf: function(){
    return this.r.exec(123)[0]
  }
}

if (a == 1 && a == 2 && a == 3) {
    console.log("!")
}

Funziona a causa del valueOfmetodo personalizzato che viene chiamato quando Object confrontato con la primitiva (come Numero). Il trucco principale è che a.valueOfrestituisce ogni volta un nuovo valore perché chiama execun'espressione regolare con gflag, il che provoca l'aggiornamento lastIndexdi quell'espressione regolare ogni volta che viene trovata una corrispondenza. Quindi prima volta this.r.lastIndex == 0, che corrisponda 1e aggiornamenti lastIndex: this.r.lastIndex == 1, quindi la prossima volta regex corrisponderà 2e così via.


22
@Abdillah un oggetto regex ricorderà l'ultimo indice a cui corrisponde, richiamando execinizierà la ricerca da quell'indice. MDN non è molto chiaro.
Simon Chan,

Vedo, quindi l' this.roggetto regex ricorda lo stato / indice. Grazie!
Abdillah,

Consiglierei di passare una stringa a exec, non un numero intero da stringere.
Bergi,

usa regex e ora hai due problemi
Aleksey Solovey,

191

Può essere realizzato utilizzando quanto segue nell'ambito globale. Da nodejsutilizzare globalanziché windownel codice seguente.

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.


Ciò presuppone che asia una proprietà di thiscui non sembra essere. Se afosse una variabile locale (che sembra), allora non funzionerebbe.
jfriend00,

1
@ jfriend00 intendi se hai inserito var a; da qualche parte?
incontro

Si. Il riferimento a == 1implica che aè una variabile da qualche parte, non una proprietà di this. Mentre c'è un posto strano come i globuli in cui entrambi potrebbero essere veri, in generale, dichiarare una variabile con var ao let asignifica che non c'è thische ti consente di accedere acome una proprietà come presuppone il tuo codice. Quindi, a quanto pare, il tuo codice assume una strana cosa variabile globale. Ad esempio, il codice non funziona in node.js e non in modalità rigorosa all'interno di una funzione. È necessario specificare le circostanze esatte in cui funziona e probabilmente spiegare perché funziona. Altrimenti, è fuorviante.
jfriend00,

@jfriend00 sicuramente. Non sono sicuro che aggiungerebbe molto più valore in combinazione con le altre risposte già. Aggiornerà la risposta
jontro,

14
La domanda era: questo "mai" sarebbe vero. E la risposta è sì, e questo è uno degli scenari in cui potrebbe essere vero: anon è una variabile locale ed è definita nell'ambito globale con un getter incrementale.
Zac Delventhal,

190

Ciò è possibile in caso di accesso variabile a, ad esempio 2 web worker tramite SharedArrayBuffer e alcuni script principali. La possibilità è bassa, ma è possibile che quando il codice viene compilato in linguaggio macchina, i lavoratori web aggiornare la variabile aappena in tempo così le condizioni a==1, a==2ea==3 sono soddisfatti.

Questo può essere un esempio di race condition in ambiente multi-thread fornito dai web worker e SharedArrayBuffer in JavaScript.

Ecco l'implementazione di base di cui sopra:

main.js

// Main Thread

const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)

modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)

worker.js

let array

Object.defineProperty(self, 'a', {
  get() {
    return array[0]
  }
});

addEventListener('message', ({data}) => {
    array = new Uint8Array(data)
    let count = 0
    do {
        var res = a == 1 && a == 2 && a == 3
        ++count
    } while(res == false) // just for clarity. !res is fine
    console.log(`It happened after ${count} iterations`)
    console.log('You should\'ve never seen this')
})

modifier.js

addEventListener('message' , ({data}) => {
    setInterval( () => {
        new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
    })
})

Sul mio MacBook Air, succede dopo circa 10 miliardi di iterazioni al primo tentativo:

inserisci qui la descrizione dell'immagine

Secondo tentativo:

inserisci qui la descrizione dell'immagine

Come ho detto, le probabilità saranno basse, ma dato il tempo sufficiente, colpirà la condizione.

Suggerimento: se il sistema impiega troppo tempo. Prova solo a == 1 && a == 2e Math.random()*3passa a Math.random()*2. Aggiungendo sempre di più all'elenco si riduce la possibilità di colpire.


50
Onestamente, questa è la risposta migliore. Tutte le altre risposte richiedono un tentativo deliberato di fare qualcosa di profondamente non intuitivo. Questa risposta in realtà riflette qualcosa che potrebbe accadere nel mondo reale: una condizione di razza.
Tom Swirly,

34
Non solo: l'ho visto accadere nel mondo reale. Non con la condizione esatta nella domanda, ma certamente con il controllo (a == 1) all'inizio di una funzione e (a == 2) in seguito nella funzione, e il codice ha raggiunto entrambe le condizioni. Cordiali saluti, la prima volta che ho visto questo accadere è stato in un controller del motore di un'auto, e abbiamo messo in atto standard di codifica. La seconda volta fu in un sistema di erogazione di pula e razzi per aerei militari, e il mio primo giorno in compagnia l' ho trovato e risolto, mentre il resto della squadra stava ancora discutendo il problema. (Kudos livello: alto! :)
Graham

38
Quindi, hai lavorato su "controller per motori di automobili" e "sistemi di erogazione di pulce e bagliori" che sono programmati in javascript con i web worker? Non credo che uscirò di nuovo fuori.
psaxton il

12
@psaxton :) Certo che no - ma abbiamo un software multi-thread con dati condivisi. Questo è un anti-pattern per tutti i software multi-thread, non specifico per Javascript o per i web worker. Non importa se stai programmando in linguaggio assembly, Brainf * ck, Visual BASIC, C o Javascript - se lo fai con dati condivisi in un'applicazione multi-thread, fallirà sempre .
Graham,

4
Penso che ora questo sia un elaborato wrapper attorno alla risposta di @ jontro.
qntm

148

Ciò è anche possibile utilizzando una serie di getter con sovrascrittura automatica:

(Questo è simile alla soluzione di jontro, ma non richiede una contro variabile.)

(() => {
    "use strict";
    Object.defineProperty(this, "a", {
        "get": () => {
            Object.defineProperty(this, "a", {
                "get": () => {
                    Object.defineProperty(this, "a", {
                        "get": () => {
                            return 3;
                        }
                    });
                    return 2;
                },
                configurable: true
            });
            return 1;
        },
        configurable: true
    });
    if (a == 1 && a == 2 && a == 3) {
        document.body.append("Yes, it’s possible.");
    }
})();


61
Si noti che anche l'approccio dell'uso di un getter funziona ===, non solo ==.
Makyen,

Questa soluzione si basa thissull'essere l'oggetto globale all'interno del corpo della funzione freccia.
Roy Tinker,

@Midnightas Non classificherei altre risposte come "codice piramidale" .
Patrick Roberts,

Nota che funziona anche con un ordine arbitrario, vero? Come (a == 3 && a == 2 && a == 1)?
Johannes,

131

In alternativa, è possibile utilizzare una classe per essa e un'istanza per il controllo.

function A() {
    var value = 0;
    this.valueOf = function () { return ++value; };
}

var a = new A;

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

MODIFICARE

Usando le classi ES6 sarebbe simile a questo

class A {
  constructor() {
    this.value = 0;
    this.valueOf();
  }
  valueOf() {
    return this.value++;
  };
}

let a = new A;

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


5
solo function A() {value = 0;all'inizio?
Dave C,

valueOfviene sovrascritto, this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codequindi quando confrontiamo il valore aumenta effettivamente di un ..
Danyal Sandeelo

130

Non vedo questa risposta già pubblicata, quindi inserirò anche questa nel mix. Questo è simile alla risposta di Jeff con lo spazio Hangul a metà larghezza.

var a = 1;
var  = 2;
var а = 3;
if(a == 1 &&  == 2 && а == 3) {
    console.log("Why hello there!")
}

Potresti notare una leggera discrepanza con la seconda, ma la prima e la terza sono identiche a occhio nudo. Tutti e 3 sono personaggi distinti:

a- Lettere minuscole latine A
- Lettere minuscole latine a larghezza intera A
а - lettere minuscole cirilliche A

Il termine generico per questo è "omogenei": diversi caratteri unicode che sembrano uguali. In genere è difficile ottenerne tre che sono assolutamente indistinguibili, ma in alcuni casi puoi essere fortunato. A, Α, А, e Ꭺ avrebbe funzionato meglio (latino-A, greca Alpha , il cirillico-A , e Cherokee-A , rispettivamente, purtroppo greca e Cherokee minuscole sono troppo diversi dal latino a: α, , e così doesn aiutare con lo snippet sopra).

Esiste un'intera classe di attacchi omogenei là fuori, più comunemente in nomi di dominio falsi (ad es. wikipediа.org(Cirillico) vs wikipedia.org(latino)), ma può anche apparire in codice; in genere indicato come subdolo (come menzionato in un commento, le domande [subdole] sono ora fuori tema su PPCG , ma era un tipo di sfida in cui si presentavano questo genere di cose). Ho usato questo sito Web per trovare gli omoglifici usati per questa risposta.


19
La "leggera discrepanza" non è come la definirei.

4
@hvd Dipende interamente dal rendering del carattere. Questo è quello che vedo .
Draco18s non si fida più di SE

1
@Jake Sì, la minuscola latina A a larghezza intera non è il massimo omogeneo (ma le varianti in maiuscolo sono sorprendenti). In genere, tuttavia, sono necessari solo due per ottenere l'effetto desiderato.
Draco18s non si fida più di SE

@ Draco18s Concordato: di solito ne servono solo 2. Ottimo lavoro anche sulle informazioni extra!
JakeSteam,

10
È inoltre possibile utilizzare il selettore varianti Unicode (U + FE00..U + FE0F). Nessuno di questi sono a: a︀ a︁ a︂. Non dovrai più preoccuparti delle discrepanze.
Salman A

108

Sì, è possibile! 😎

»JavaScript

if‌=()=>!0;
var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    document.write("<h1>Yes, it is possible!😎</h1>")
}

Il codice sopra è una versione breve (grazie a @Forivin per la sua nota nei commenti) e il seguente codice è originale:

var a = 9;

if‌(a==1 && a== 2 && a==3)
{
    //console.log("Yes, it is possible!😎")
    document.write("<h1>Yes, it is possible!😎</h1>")
}

//--------------------------------------------

function if‌(){return true;}

Se vedi solo il lato superiore del mio codice ed eseguilo dici WOW, come?

Quindi penso che sia sufficiente dire Sì, è possibile per qualcuno che ti ha detto: Niente è impossibile

Trucco: ho usato un personaggio nascosto dopo ifper creare una funzione a cui il suo nome è simile if. In JavaScript non possiamo ignorare le parole chiave, quindi ho costretto a utilizzare in questo modo. È un falso if, ma in questo caso funziona per te!


» C #

Inoltre ho scritto una versione C # ( con tecnica di aumento del valore della proprietà ):

static int _a;
public static int a => ++_a;

public static void Main()
{
    if(a==1 && a==2 && a==3)
    {
        Console.WriteLine("Yes, it is possible!😎");
    }
}

Dimostrazione dal vivo


56
La versione javascript è un vero crimine contro l'umanità e la capacità di farlo, dovrebbe essere illegale secondo le convenzioni dell'ONU. Penso che sia giunto il momento di eliminare il mondo da ogni conoscenza di javacript.
Più chiaro il

2
La dichiarazione di funzione potrebbe essere ancora più breve. if‌=()=>!0
Forivin,

4
Perché mai hai usato document.write? Questo è un modo infallibile per non essere assunto indipendentemente dal resto della risposta.
Cerbrus,

3
@Cerbrus, grazie per la tua nota. Ho scritto prima la mia risposta con console.logma l'ho cambiata in document.write. Uso sempre sempre i console.logmiei codici ma qui voglio solo mostrare un testo agli utenti nella casella dello snippet di codice StackOverflow. Quindi volevo mostrare il mio messaggio più bello del messaggio generato da console.log. Fai clic sul Run Code Snippetpulsante sulla mia risposta e su altre risposte. Lo snippet di codice SO mi ha permesso di utilizzare html, JS e CSS, quindi ho voluto utilizzarlo nella mia risposta e renderlo piacevole. Penso che non abbia alcun effetto collaterale negativo e non abbia reso la mia risposta ampia o conforme.
RAM

1
@Clearer, se le convenzioni delle Nazioni Unite potrebbero cambiare il mondo in modo efficace, allora dovremmo avere un mondo migliore di questo. Abbiamo bisogno di qualcosa di più della semplice dichiarazione delle Nazioni Unite e fino a quel giorno penso di poter usare questo mio trucco Javascript;)
RAM

97

JavaScript

a == a +1

In JavaScript, non ci sono numeri interi ma solo Numbers, che sono implementati come numeri in virgola mobile a precisione doppia.

Significa che se un numero aè abbastanza grande, può essere considerato uguale a tre numeri interi consecutivi:

a = 100000000000000000
if (a == a+1 && a == a+2 && a == a+3){
  console.log("Precision loss!");
}

È vero, non è esattamente quello che l'intervistatore ha chiesto (non funziona con a=0), ma non comporta alcun trucco con funzioni nascoste o sovraccarico dell'operatore.

Altre lingue

Per riferimento, ci sono a==1 && a==2 && a==3soluzioni in Ruby e Python. Con una leggera modifica, è possibile anche in Java.

Rubino

Con un'abitudine ==:

class A
  def ==(o)
    true
  end
end

a = A.new

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

O un aumento a:

def a
  @a ||= 0
  @a += 1
end

if a == 1 && a == 2 && a == 3
  puts "Don't do this!"
end

Pitone

class A:
    def __eq__(self, who_cares):
        return True
a = A()

if a == 1 and a == 2 and a == 3:
    print("Don't do that!")

Giava

È possibile modificare la Integercache Java :

package stackoverflow;

import java.lang.reflect.Field;

public class IntegerMess
{
    public static void main(String[] args) throws Exception {
        Field valueField = Integer.class.getDeclaredField("value");
        valueField.setAccessible(true);
        valueField.setInt(1, valueField.getInt(42));
        valueField.setInt(2, valueField.getInt(42));
        valueField.setInt(3, valueField.getInt(42));
        valueField.setAccessible(false);

        Integer a = 42;

        if (a.equals(1) && a.equals(2) && a.equals(3)) {
            System.out.println("Bad idea.");
        }
    }
}

27
@ cᴏʟᴅsᴘᴇᴇᴅ: Java, Javascript, potayto, potahto :) Ci sono già abbastanza buone risposte JS. Ho solo pensato che sarebbe interessante mostrare come si può fare in altre lingue e possibilmente dare qualche idea agli sviluppatori JS.
Eric Duminil,

2
@ cᴏʟᴅsᴘᴇᴇᴅ: aggiornato con un esempio di JS.
Eric Duminil,

1
Perché la versione Java non funziona Integer a = 42(o funziona)? Per quanto ho capito autoboxing, Integer a = 42; a == 1 && a == 2 && a == 3dovrebbe box tutti gli ints. O questo unbox a per i confronti?
CAD97,

@ CAD97: Integer == intsembra provocare unboxing. Ma usando le Integer#equals(int)forze autoboxing, quindi funziona. Grazie per il commento!
Eric Duminil,

@StephanBijzitter: Per favore, spiega. Per quanto ne so, ci sono solo Numbersin JS, che sono fondamentalmente come doubles. Possono sembrare numeri interi e puoi usarli come numeri interi, ma non sono ancora numeri interi. Non credo che n == n + 1possa mai essere vero per gli interi in Java / Python / C / Ruby / ...
Eric Duminil,

80

Questa è una versione invertita della risposta di @ Jeff * in cui un carattere nascosto (U + 115F, U + 1160 o U + 3164) viene utilizzato per creare variabili simili a 1, 2e 3.

var  a = 1;
var 1 = a;
var 2 = a;
var 3 = a;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );

* Questa risposta può essere semplificata utilizzando non-joiner a larghezza zero (U + 200C) e joiner a larghezza zero (U + 200D). Entrambi questi personaggi sono consentiti all'interno di identificatori ma non all'inizio:

var a = 1;
var a = 2;
var a = 3;
console.log(a == 1 && a == 2 && a == 3);

/****
var a = 1;
var a\u200c = 2;
var a\u200d = 3;
console.log(a == 1 && a\u200c == 2 && a\u200d == 3);
****/

Altri trucchi sono possibili utilizzando la stessa idea, ad esempio utilizzando i selettori di variazione Unicode per creare variabili che si assomigliano esattamente ( a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).


75

Regola numero uno delle interviste; mai dire impossibile.

Non c'è bisogno di ingannare i personaggi nascosti.

window.__defineGetter__( 'a', function(){
    if( typeof i !== 'number' ){
        // define i in the global namespace so that it's not lost after this function runs
        i = 0;
    }
    return ++i;
});

if( a == 1 && a == 2 && a == 3 ){
    alert( 'Oh dear, what have we done?' );
}


6
Ahia. __defineGetter__in realtà non fa parte del linguaggio js, ​​solo una brutta versione di defineProperty. typeofnon è una funzione e questo non dichiarato iè semplicemente orribile. Sembra che valga ancora 40 voti: /
Jonas Wilms il

6
@JonasW. 41 voti :-) Sono consapevole che __defineGetter__è deprecato per developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ma si esegue chiaramente nel mio FireFox v 57.0.4, quindi ho optato per mostrare questo invece di defineProperty()perché il codice legacy è reale e non può essere ignorato. Indipendentemente dalla bruttezza, dichiarare icome ho fatto è un comportamento ben noto / documentato. Forse ero solo di umore PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus

68

Sinceramente, se c'è un modo per valutarlo come vero o no (e come altri hanno dimostrato, ci sono molti modi), la risposta che cerco, parlando come qualcuno che ha condotto centinaia di interviste, sarebbe qualcosa sulla falsariga di:

"Beh, forse sì in alcune strane circostanze che non sono immediatamente ovvie per me ... ma se lo avessi riscontrato nel codice reale, avrei usato tecniche di debug comuni per capire come e perché stesse facendo quello che stava facendo e quindi riformattare immediatamente il codice per evitare quella situazione ... ma soprattutto: non scriverò MAI assolutamente quel codice in primo luogo perché quella è la definizione stessa di codice contorto, e mi sforzo di non scrivere mai codice contorto ".

Immagino che alcuni intervistatori si offenderebbero per aver chiamato quella che è ovviamente intesa come una domanda molto delicata, ma non mi dispiace che gli sviluppatori abbiano un'opinione, soprattutto quando possono sostenerla con un pensiero ragionato e possono inserire la mia domanda in una dichiarazione significativa su se stessi.


13
La domanda (o tutte le domande del colloquio) è probabilmente quella di testare la volontà dei candidati di pensare a un problema, specialmente quelli che sono "apparentemente ovvi", come questo. Qualcuno che rifiuta di pensare perché crede di "conoscere" la risposta non è un buon ingaggio.
Shammoo,

5
@Don Hatch No, non li penalizzerei se rispondessero in buona fede e soprattutto se fornissero una risposta corretta come quelle mostrate da altri ... ma vorrei quindi chiedere un follow-up per provare a sondare se pensano che sia un buon modo per scrivere codice o no. Essere informati e riuscire a trovare una risposta "corretta" è solo una parte dell'essere un buon sviluppatore. Molto più importante per uno sviluppatore "professionale" è scrivere codice che sia comprensibile e gestibile lungo la strada, spesso volte da sviluppatori meno capaci. Gli sviluppatori troppo intelligenti sono praticamente cattivi quanto quelli incapaci dell'IME.
Frank W. Zammetti,

16
Questo non risponde alla domanda.
TylerH,

6
La cosa triste di questa risposta è che un utente di 1rep ha risposto ieri e ha ottenuto 2 voti negativi facendogli eliminare questa domanda.
Jonas Wilms,

8
@JohnColeman la domanda chiede come il codice potrebbe essere considerato vero. Non pone in primo luogo i motivi per cui l'intervistatore ha proposto la domanda. Questa risposta non tenta nemmeno di rispondere alla domanda posta, ma si concentra interamente su una versione "cosa farei" di un tentativo di indovinare quale fosse lo scopo dell'intervistatore. Se questa fosse la domanda posta, sarebbe troppo ampia. Pertanto questa risposta non appartiene qui o in qualsiasi parte del sito.
TylerH,

43

Se ricevi mai una domanda del genere (o noti un comportamento altrettanto imprevisto nel tuo codice), pensa a che tipo di cose potrebbero causare un comportamento che sembra impossibile a prima vista:

  1. Codifica : in questo caso la variabile che stai osservando non è quella che pensi sia. Questo può accadere se si scherza intenzionalmente con Unicode usando omogenei o caratteri spaziali per far apparire il nome di una variabile come un altro, ma i problemi di codifica possono anche essere introdotti accidentalmente, ad esempio quando si copia e incolla codice dal Web che contiene codice Unicode imprevisto punti (ad es. perché un sistema di gestione dei contenuti ha effettuato una "formattazione automatica" come la sostituzione flcon Unicode "LATIN SMALL LIGATURE FL" (U + FB02)).

  2. Condizioni di gara : potrebbe verificarsi una condizione di gara , ovvero una situazione in cui il codice non viene eseguito nella sequenza prevista dallo sviluppatore. Le condizioni di competizione si verificano spesso nel codice multi-thread, ma più thread non sono un requisito per rendere possibili le condizioni di gara: l'asincronicità è sufficiente (e non confondersi, asincronizzazione non significa che vengano utilizzati thread multipli sotto il cofano ).

    Pertanto, JavaScript non è privo di condizioni di gara solo perché è a thread singolo. Vedere qui per un semplice esempio a thread singolo, ma asincrono. Nel contesto di una singola affermazione, tuttavia, le condizioni di gara sarebbero piuttosto difficili da raggiungere in JavaScript.

    JavaScript con i web worker è un po 'diverso, poiché puoi avere più thread. @mehulmpt ci ha mostrato una grande dimostrazione del concetto usando i web worker .

  3. Effetti collaterali : un effetto collaterale dell'operazione di confronto sull'uguaglianza (che non deve essere così ovvio come negli esempi qui, spesso gli effetti collaterali sono molto sottili).

Questo tipo di problemi può apparire in molti linguaggi di programmazione, non solo JavaScript, quindi non stiamo vedendo uno dei WTF JavaScript classici qui 1 .

Naturalmente, la domanda dell'intervista e i campioni qui sembrano tutti molto elaborati. Ma ricordano che:

  • Gli effetti collaterali possono diventare davvero sgradevoli e un programma ben progettato dovrebbe essere privo di effetti collaterali indesiderati.
  • Il multithreading e lo stato mutabile possono essere problematici.
  • Non eseguire correttamente la codifica dei caratteri e l'elaborazione delle stringhe può portare a cattivi bug.

1 Ad esempio, puoi trovare un esempio in un linguaggio di programmazione (C #) completamente diverso che mostra un effetto collaterale (evidente) qui .


1
Quindi, la domanda diventa troppo ampia. Lingue diverse possono implementarlo con vari gradi di facilità. La domanda ha guadagnato molta trazione perché è una domanda e risposta specifica di JS, ma questo è solo il mio 2c.
cs95,

1
le cause sono C # e javascript differenti, quindi questa risposta non è legittima.
Edwin,

3
@Edwin: Le cause sono esattamente le stesse: Unicode giocherellare con glifi o caratteri spaziali simili, condizioni di gara o effetti collaterali dell'operazione di confronto (quest'ultimo mostrato nel mio esempio).
Dirk Vollmar,

2
@ cᴏʟᴅsᴘᴇᴇᴅ: a volte guardare le cose da una prospettiva più ampia aiuta a vedere il problema reale.
Dirk Vollmar,

3
Vorrei che questa risposta potesse essere taggata su questa domanda in qualche modo "meta". Dopo aver letto tutte le risposte sopra, mi è stato lasciato come se JS avesse così tanti buchi, ma hai riassunto tutte le risposte in una volta sola. E l'hai fatto in un modo che lo rende una domanda per un'intervista stellare (se il tag specifico della lingua viene rimosso) secondo me. Bravo!
KCE,

41

Ecco un'altra variante, utilizzando un array per estrarre qualsiasi valore tu voglia.

const a = {
  n: [3,2,1],
  toString: function () {
    return a.n.pop();
  }
}

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


31

Va bene, un altro hack con generatori:

const value = function* () {
  let i = 0;
  while(true) yield ++i;
}();

Object.defineProperty(this, 'a', {
  get() {
    return value.next().value;
  }
});

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


Dici hack, ma sono abbastanza sicuro che questo è il caso d'uso dei generatori ... :) (beh, tranne per il fatto che si basa thissull'essere l'oggetto finestra)
Cody G

29

Utilizzo dei proxy :

var a = new Proxy({ i: 0 }, {
    get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);

I proxy sostanzialmente fingono di essere un oggetto target (il primo parametro), ma intercettano le operazioni sull'oggetto target (in questo caso l'operazione "get property") in modo che ci sia un'opportunità di fare qualcosa di diverso dal comportamento dell'oggetto predefinito. In questo caso, l'azione "get property" viene chiamata aquando ==costringe il suo tipo per confrontarlo con ciascun numero. Questo succede:

  1. Creiamo un oggetto target { i: 0 }, dove ili proprietà è il nostro contatore
  2. Creiamo un proxy per l'oggetto target e lo assegniamo a a
  3. Per ogni a ==confronto, ail tipo è costretto a un valore primitivo
  4. Questo tipo di coercizione comporta una chiamata a[Symbol.toPrimitive]()interna
  5. Il proxy intercetta ottenere la a[Symbol.toPrimitive]funzione usando il "get handler"
  6. Del proxy "get handler" controlla che la proprietà di essere ammassato è Symbol.toPrimitive, nel qual caso si incrementa e poi ritorna al banco da l'oggetto di destinazione: ++target.i. Se viene recuperata una proprietà diversa, torniamo semplicemente a restituire il valore predefinito della proprietà,target[name]

Così:

var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3    // a == ++target.i == 3

Come con la maggior parte delle altre risposte, questo funziona solo con un controllo di uguaglianza libero ( ==), poiché controlli di uguaglianza rigorosi ( ===) non generano coercizione che il proxy può intercettare.


2
Non ha senso utilizzare un proxy per questo, però: definire Symbol.toPrimitiveallo stesso modo su un oggetto funzionerebbe altrettanto bene.
Ry-

27

In realtà la risposta alla prima parte della domanda è "Sì" in ogni linguaggio di programmazione. Ad esempio, questo è nel caso di C / C ++:

#define a   (b++)
int b = 1;
if (a ==1 && a== 2 && a==3) {
    std::cout << "Yes, it's possible!" << std::endl;
} else {
    std::cout << "it's impossible!" << std::endl;
}

27
Non credo sia possibile in tutti i linguaggi di programmazione. Ad esempio, non tutte le lingue dispongono di preprocessori. Del resto, non tutte le lingue usano &&logicamente "e".
Keith Thompson,

3
Ho trovato un modo che funziona sia in Python che in C ++ che utilizza il sovraccarico dell'operatore.
Paperino

7
E puoi farlo in Java usando reflection e rovinando la cache dei numeri interi.
CAD97

7
Non posso farlo in lingue che non supportano la mutazione in quel punto, ad es. Nulla di paragonabile è disponibile in haskell
Jason Carr

4
La domanda è su JavaScript, non su C ++.
Tutti i lavoratori sono essenziali il

26

Stesso, ma diverso, ma sempre uguale (può essere "testato" più volte):

const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1}
    
if(a == 1 && a == 2 && a == 3) {
  console.log('Hello World!');
}

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

La mia idea è nata da come funziona l'equazione del tipo di oggetto Numero.


4
Funziona anche la seconda volta!
Salman A

25

Una risposta ECMAScript 6 che utilizza simboli:

const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));

A causa di ==utilizzo, si suppone Javascript per costringere ain qualcosa di vicino al secondo operando ( 1, 2, 3in questo caso). Ma prima che JavaScript provi a calcolare il coercing da solo, prova a chiamare Symbol.toPrimitive. Se si fornisce Symbol.toPrimitiveJavaScript, verrà utilizzato il valore restituito dalla funzione. In caso contrario, JavaScript chiamerebbe valueOf.


24

Penso che questo sia il codice minimo per implementarlo:

i=0,a={valueOf:()=>++i}

if (a == 1 && a == 2 && a == 3) {
  console.log('Mind === Blown');
}

Creazione di un oggetto fittizio con un'abitudine valueOfche incrementa una variabile globale isu ogni chiamata. 23 personaggi!


14

Questo usa la definizioneProperty con un piacevole effetto collaterale che causa una variabile globale!

var _a = 1

Object.defineProperty(this, "a", {
  "get": () => {
    return _a++;
  },
  configurable: true
});

console.log(a)
console.log(a)
console.log(a)


8
potresti usare una chiusura a: get: (a => () => ++a)(0),nessun globale necessario.
Nina Scholz,

13
@NinaScholz certo, ma stiamo parlando di cattive pratiche qui - fammi avere questo: D
Ben Aubin

1

Sostituendo valueOfuna dichiarazione di classe, si può fare:

class Thing {
    constructor() {
        this.value = 1;
    }

    valueOf() {
        return this.value++;
    }
}

const a = new Thing();

if(a == 1 && a == 2 && a == 3) {
    console.log(a);
}

Quello che succede è che valueOfviene chiamato in ciascun operatore di confronto. Sul primo asarà uguale 1, sul secondo asarà uguale 2e così via, e così via, perché ogni volta che valueOfviene chiamato, il valore di aviene incrementato.

Pertanto console.log verrà generato ed emesso (comunque nel mio terminale) Thing: { value: 4}, indicando che il condizionale era vero.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.