Frage Kann (a == 1 && a == 2 && a == 3) jemals als wahr bewertet werden?


Moderator Hinweis: Bitte widerstehen Sie dem Drang, den Code zu bearbeiten oder entfernen Sie diesen Hinweis. Das Muster von Leerzeichen kann Teil der Frage sein und sollte daher nicht unnötig manipuliert werden. Wenn Sie sich im Camp "Whitespace is insignificant" befinden, sollten Sie den Code so akzeptieren können, wie er ist.

Ist das jemals möglich? (a== 1 && a ==2 && a==3) könnte bewerten true in JavaScript?

Dies ist eine Interviewfrage, die von einem großen Technologieunternehmen gestellt wird. Es ist vor zwei Wochen passiert, aber ich versuche immer noch, die Antwort zu finden. Ich weiß, dass wir in unserer täglichen Arbeit niemals solchen Code schreiben, aber ich bin neugierig.


2250
2018-01-15 20:20


Ursprung


Antworten:


Wenn Sie davon profitieren Wie == funktioniert, könnten Sie einfach ein Objekt mit einem benutzerdefinierten erstellen toString (oder valueOf) Funktion, die das, was sie jedes Mal zurückgibt, so ändert, dass sie alle drei Bedingungen erfüllt.

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

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


Der Grund dafür liegt in der Verwendung des losen Gleichheitsoperators. Wenn einer der Operanden bei der Verwendung von loser Gleichheit einen anderen Typ als der andere hat, versucht die Engine, die eine in die andere umzuwandeln. Bei einem Objekt auf der linken Seite und einer Zahl auf der rechten Seite wird versucht, das Objekt durch einen ersten Aufruf in eine Zahl umzuwandeln valueOf Wenn es abrufbar ist, und wenn dies nicht der Fall ist, wird es angerufen toString. ich benutzte toString in diesem Fall, einfach weil es in den Sinn kam, valueOf würde mehr Sinn machen. Wenn ich stattdessen eine Zeichenfolge aus zurückgegeben habe toStringhätte die Engine dann versucht, die Zeichenfolge in eine Zahl umzuwandeln, die uns das gleiche Endergebnis liefert, allerdings mit einem etwas längeren Pfad.


3091
2018-01-15 20:35



Ich konnte nicht widerstehen - die anderen Antworten sind zweifellos richtig, aber Sie können wirklich nicht über den folgenden Code gehen:

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

Beachten Sie den seltsamen Abstand in der if Aussage (die ich von deiner Frage kopiert habe). Es ist das Hangul halber Breite (das ist Koreanisch für diejenigen, die nicht vertraut sind), das ein Unicode-Leerzeichen ist, das vom ECMA-Skript nicht als Leerzeichen interpretiert wird - das bedeutet, dass es ein gültiges Zeichen für einen Bezeichner ist. Daher gibt es drei völlig verschiedene Variablen, eine mit dem Hangul nach der a, eine mit der davor und die letzte mit nur einer. Ersetzen Sie den Raum mit _ zur besseren Lesbarkeit würde der gleiche Code wie folgt aussehen:

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

Auschecken die Validierung des Variablennamen-Validators von Mathias. Wenn dieser seltsame Abstand tatsächlich in ihrer Frage enthalten ist, bin ich sicher, dass es ein Hinweis für diese Art von Antwort ist.

Tu das nicht. Ernst.

Edit: Es ist mir aufgefallen, dass (obwohl eine Variable nicht gestartet werden darf) Null Breiten Schreiner und Zero-width non-joiner Zeichen sind auch in Variablennamen erlaubt - siehe Verschleierung von JavaScript mit Null-Breite-Zeichen - Pro und Contra?.

Dies würde wie folgt aussehen:

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!")
}


1914
2018-01-16 05:14



ES IST MÖGLICH!

var i = 0;

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

Dies verwendet einen Getter innerhalb eines with Aussage zu lassen a werte zu drei verschiedenen Werten aus.

... das bedeutet immer noch nicht, dass dies in echtem Code verwendet werden sollte ...


565
2018-01-15 20:35



Beispiel ohne getters oder valueOf:

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

Das funktioniert weil == ruft auf toString welches anruft .join für Arrays.

Eine andere Lösung, mit Symbol.toPrimitive Das ist ein ES6-Äquivalent von toString/valueOf:

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

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


428
2018-01-17 11:37



Wenn es gefragt wird, ob es möglich ist (nicht MUSS), kann es "a" bitten, eine Zufallszahl zurückzugeben. Es wäre wahr, wenn es nacheinander 1, 2 und 3 erzeugt.

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;
    }
  }
}


249
2018-01-16 06:21



Wenn Sie nichts ohne reguläre Ausdrücke tun können:

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

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

Es funktioniert wegen der Gewohnheit valueOf Methode, die aufgerufen wird, wenn Object mit einem primitiven Element verglichen wird (z. B. Number). Haupttrick ist das a.valueOf gibt jedes Mal einen neuen Wert zurück, weil es anruft exec auf regulärem Ausdruck mit g Flag, das die Aktualisierung verursacht lastIndex von diesem regulären Ausdruck jedes Mal, wenn Übereinstimmung gefunden wird. Also zum ersten Mal this.r.lastIndex == 0, es passt 1 und Updates lastIndex: this.r.lastIndex == 1, also wird die nächste Zeit Regex übereinstimmen 2 und so weiter.


195
2018-01-16 19:35



Dies kann unter Verwendung des folgenden im globalen Gültigkeitsbereich erreicht werden. Zum nodejs benutzen global Anstatt von window im folgenden Code.

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

Diese Antwort missbraucht die im globalen Kontext im Ausführungskontext bereitgestellten impliziten Variablen, indem ein Getter zum Abrufen der Variablen definiert wird.


183
2018-01-15 20:37



Dies ist im Falle einer Variablen möglich a Zugriff von, sagen wir 2 Web-Arbeiter über einen SharedArrayBuffer sowie einige Hauptskript. Die Möglichkeit ist gering, aber es ist möglich, dass die Web-Worker die Variable aktualisieren, wenn der Code in den Maschinencode kompiliert wird a gerade rechtzeitig so die Bedingungen a==1, a==2 und a==3 sind zufrieden.

Dies kann ein Beispiel für eine Race Condition in einer Umgebung mit mehreren Threads sein, die von Web Worker und SharedArrayBuffer in JavaScript bereitgestellt wird.

Hier ist die grundlegende Implementierung von oben:

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
    })
})

Auf meinem MacBook Air passiert es nach etwa 10 Milliarden Iterationen beim ersten Versuch:

enter image description here

Zweiter Versuch:

enter image description here

Wie gesagt, die Chancen werden niedrig sein, aber wenn genügend Zeit gegeben ist, wird es den Zustand treffen.

Tipp: Wenn es auf Ihrem System zu lange dauert. Nur versuchen a == 1 && a == 2 und ändern Math.random()*3 zu Math.random()*2. Wenn Sie der Liste mehr und mehr hinzufügen, wird die Wahrscheinlichkeit eines Treffers verringert.


171
2018-01-17 07:39



Dies ist auch mit einer Reihe von selbstüberschreibenden Gettern möglich:

(Dies ist der Lösung von jontro ähnlich, erfordert jedoch keine Zählervariable.)

(() => {
    "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.");
    }
})();


141
2018-01-16 11:37



Ich sehe diese Antwort nicht schon gepostet, also werde ich diese auch in die Mischung werfen. Das ist ähnlich wie Jeffs Antwort mit dem halbbreiten Hangul-Raum.

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

Sie können eine leichte Diskrepanz mit der zweiten bemerken, aber die erste und dritte sind identisch mit dem bloßen Auge. Alle 3 sind unterschiedliche Charaktere:

a - lateinischer Kleinbuchstabe A
 - Vollbreite Latein Kleinbuchstaben A
а - Kyrillisch Kleinbuchstaben A

Der generische Ausdruck dafür ist "Homoglyphen": verschiedene Unicode-Zeichen, die gleich aussehen. Normalerweise schwer zu bekommen drei Das ist völlig ununterscheidbar, aber in manchen Fällen kann man Glück haben. A, Α,, und Ꭺ würden besser funktionieren (Latin-A, Griechisches Alpha, Kyrillisch-A, und Cherokee-A beziehungsweise; leider sind die Kleinbuchstaben Griechisch und Cherokee zu verschieden vom Lateinischen a: α,, und so hilft nicht mit dem obigen Ausschnitt).

Es gibt eine ganze Klasse von Homoglyph-Attacken, am häufigsten in gefälschten Domainnamen (z. B. wikipediа.org (Kyrillisch) vs wikipedia.org (Latein)), aber es kann sich auch im Code zeigen; in der Regel als hinterhältig bezeichnet (wie in einem Kommentar erwähnt, [hinterhältig] Fragen sind jetzt off-topic auf PPCG, aber war eine Art von Herausforderung, wo diese Art von Dingen auftauchen würde). ich benutzte Diese Internetseite um die für diese Antwort verwendeten Homoglyphen zu finden.


125
2018-01-16 18:44