it-swarm.com.de

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

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

Ist es überhaupt möglich, dass (a== 1 && a ==2 && a==3) in JavaScript zu true ausgewertet wird?

Dies ist eine Interviewfrage, die von einem großen Tech-Unternehmen gestellt wurde. Es ist vor zwei Wochen passiert, aber ich versuche immer noch die Antwort zu finden. Ich weiß, dass wir im Alltag keinen solchen Code schreiben, aber ich bin neugierig.

2331

Wenn Sie wie == funktioniert nutzen, können Sie einfach ein Objekt mit einer benutzerdefinierten toString (oder valueOf) -Funktion erstellen, die die zurückgegebenen Werte bei jeder Verwendung so ändert, dass alle drei Bedingungen erfüllt werden.

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

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


Der Grund, warum dies funktioniert, liegt in der Verwendung des lockeren Gleichheitsoperators. Wenn bei einer lockeren Gleichheit einer der Operanden einen anderen Typ als der andere hat, versucht die Engine, einen in den anderen umzuwandeln. Bei einem Objekt links und einer Zahl rechts wird versucht, das Objekt in eine Zahl umzuwandeln, indem zuerst valueOf aufgerufen wird, sofern es aufrufbar ist. Andernfalls wird toString aufgerufen. Ich habe in diesem Fall toString verwendet, weil valueOf einfach mehr Sinn macht. Wenn ich stattdessen eine Zeichenfolge von toString zurückgegeben habe, hätte die Engine versucht, die Zeichenfolge in eine Zahl umzuwandeln, die dasselbe Endergebnis liefert, jedoch mit einem etwas längeren Pfad.

3185
Kevin B

Ich kann nicht widerstehen - die anderen Antworten sind zweifellos wahr, aber Sie können den folgenden Code wirklich nicht passieren:

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-Anweisung (den ich aus Ihrer Frage kopiert habe). Das halbe Hangul (das ist Koreanisch für diejenigen, die nicht vertraut sind) ist ein Unicode-Leerzeichen, das vom ECMA-Skript nicht als Leerzeichen interpretiert wird. Dies bedeutet, dass es ein gültiges Zeichen für einen Bezeichner ist. Daher gibt es drei völlig verschiedene Variablen, eine mit dem Hangul hinter dem a, eine mit dem vorherigen und die letzte mit nur einem. Um den Speicherplatz aus Gründen der Lesbarkeit durch _ zu ersetzen, würde derselbe Code folgendermaßen aussehen:

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

Check out die Validierung von Mathias 'Variablennamen-Validator . Wenn dieser seltsame Abstand tatsächlich in ihrer Frage enthalten war, bin ich mir sicher, dass dies ein Hinweis auf diese Art von Antwort ist.

Tu das nicht. Ernst.

Edit: Es ist mir aufgefallen, dass (auch wenn keine Variable gestartet werden darf) die Zero-Width-Joiner und Zero-Width-Nicht-Joiner - Zeichen in Variablennamen zulässig sind - siehe Verschleierung JavaScript mit Zero-Width-Zeichen - Vor- und Nachteile? .

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

1969
Jeff

IT IS MÖGLICH!

var i = 0;

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

Hierbei wird ein Getter in einer with-Anweisung verwendet, damit a drei verschiedene Werte ermitteln kann.

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

Noch schlimmer ist, dass dieser Trick auch mit === funktioniert.

  var i = 0;

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

591
Jonas Wilms

Beispiel ohne Getter oder WertOf:

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

Dies funktioniert, weil ==toString aufruft, die .join für Arrays aufruft.

Eine andere Lösung, die Symbol.toPrimitive verwendet, ist ein ES6-Äquivalent von toString/valueOf

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

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

458
georg

Wenn gefragt wird, ob dies möglich ist (nicht MUSS), kann "a" aufgefordert werden, eine Zufallszahl zurückzugeben. Es wäre wahr, wenn es 1, 2 und 3 nacheinander 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;
    }
  }
}

259
mmmaaa

Wenn Sie ohne reguläre Ausdrücke nichts 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 aufgrund der benutzerdefinierten valueOf -Methode, die aufgerufen wird, wenn Object mit einem primitiven Element (z. B. Number) verglichen wird. Der Haupttrick ist, dass a.valueOf jedes Mal einen neuen Wert zurückgibt, da er exec für einen regulären Ausdruck mit g-Flag aufruft, was zu einer Aktualisierung von lastIndex dieses regulären Ausdrucks führt, wenn Übereinstimmung gefunden wird. Beim ersten Mal this.r.lastIndex == 0 stimmt es mit 1 überein und aktualisiert lastIndex: this.r.lastIndex == 1, so dass das nächste Mal, wenn der Regex 2 und so weiter übereinstimmt.

203
Kos

Dies kann im globalen Bereich unter Verwendung der folgenden Schritte ausgeführt werden. Für nodejs verwenden Sie global anstelle von window im nachstehenden 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 impliziten Variablen, die vom globalen Gültigkeitsbereich im Ausführungskontext bereitgestellt werden, indem ein Getter zum Abrufen der Variablen definiert wird.

186
jontro

Dies ist möglich, wenn auf die Variable a von beispielsweise zwei Web-Workern über einen SharedArrayBuffer sowie ein Hauptskript zugegriffen wird. Die Möglichkeit ist gering, aber wenn der Code zu Maschinencode kompiliert wird, aktualisieren die Web-Worker die Variable a gerade rechtzeitig, damit die Bedingungen a==1, a==2 und a==3 erfüllt sind.

Dies kann ein Beispiel für die Race-Bedingung in einer Multithread-Umgebung sein, die von Web Workern 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 geschieht dies nach etwa 10 Milliarden Iterationen beim ersten Versuch:

 enter image description here

Zweiter Versuch:

 enter image description here

Wie gesagt, die Chancen sind gering, aber bei ausreichender Zeit trifft dies die Bedingung.

Tipp: Wenn es auf Ihrem System zu lange dauert. Versuchen Sie nur a == 1 && a == 2 und ändern Sie Math.random()*3 in Math.random()*2. Durch das Hinzufügen von mehr und mehr Listen wird die Trefferchance verringert.

182
mehulmpt

Dies ist auch mit einer Reihe selbstschreibender Getter möglich:

(Dies ist ähnlich der Lösung von Jontro, 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.");
    }
})();

145
Patrick Dark

Ich sehe diese Antwort noch nicht, also werde ich sie auch in den Mix einfließen lassen. Dies ist ähnlich wie Jeffs Antwort mit dem Hangul-Raum halber Breite.

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

Möglicherweise stellen Sie eine leichte Abweichung von der zweiten fest, aber die erste und dritte Abweichung sind mit dem bloßen Auge identisch. Alle 3 sind verschiedene Zeichen:

a - Lateinischer Kleinbuchstabe A
- Lateinische Kleinbuchstaben in voller Breite A
а - Kyrillische Kleinbuchstaben A

Der Oberbegriff dafür ist "Homoglyphen": verschiedene Unicode-Zeichen, die gleich aussehen. Normalerweise sind drei schwer zu bekommen , die absolut nicht zu unterscheiden sind, aber in manchen Fällen kann man Glück haben. A, Α, А und Ꭺ würden besser funktionieren (Latein-A, Griechisches Alpha , Kyrillisch-A und Cherokee-A ; Leider unterscheiden sich die griechischen und Cherokee-Kleinbuchstaben zu stark vom lateinischen a: α, und hilft daher nicht mit dem obigen Snippet).

Es gibt eine ganze Klasse von Homoglyphenangriffen, am häufigsten in gefälschten Domainnamen (z. B. wikipediа.org (Kyrillisch) vs wikipedia.org (Latin)), aber es kann auch im Code angezeigt werden; Normalerweise wird dies als Unterhandlung bezeichnet (wie in einem Kommentar erwähnt, [Unterhandlung] Fragen sind jetzt nicht mehr aktuell PPCG , aber Früher war es eine Art Herausforderung, bei der solche Dinge auftauchten. Ich habe diese Website verwendet, um die Homoglyphen zu finden, die für diese Antwort verwendet wurden.

129
Draco18s

Alternativ können Sie eine Klasse dafür und eine Instanz für die Prüfung verwenden.

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

var a = new A;

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

EDIT

Mit ES6-Klassen würde es so aussehen

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!');
}

123
Nina Scholz

Ja, es ist möglich! ????

"JavaScript

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

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

Der obige Code ist eine Kurzversion (danke an @Forivin für den Hinweis in den Kommentaren) und der folgende Code ist original:

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

Wenn Sie nur die Oberseite meines Codes sehen und ihn ausführen, sagen Sie WOW, wie?

Ich denke es ist genug zu sagen Ja, das ist möglich zu jemandem, der zu dir gesagt hat: Nichts ist unmöglich

Trick: Ich habe nach if ein verstecktes Zeichen verwendet, um eine Funktion zu erstellen, deren Name if ähnelt. In JavaScript können wir Schlüsselwörter nicht überschreiben, so dass ich gezwungen bin, diese Methode zu verwenden. Es ist eine Fälschung if, aber es funktioniert in diesem Fall für Sie!


" C #

Außerdem habe ich eine C # -Version geschrieben ( mit Technik zum Erhöhen des Eigenschaftswerts):

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

Live Demo

101
RAM

JavaScript

a == a +1

In JavaScript gibt es keine Ganzzahlen , sondern nur Numbers, die als Gleitkommazahlen mit doppelter Genauigkeit implementiert sind.

Wenn eine Zahl a groß genug ist, kann dies als drei aufeinander folgende Ganzzahlen betrachtet werden:

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

Es ist zwar nicht genau das, was der Interviewer gefragt hat (es funktioniert nicht mit a=0), aber es bringt keinen Trick mit verborgenen Funktionen oder der Überladung von Operatoren mit sich.

Andere Sprachen

Als Referenz gibt es in Ruby und Python a==1 && a==2 && a==3-Lösungen. Mit einer geringfügigen Änderung ist es auch in Java möglich.

Rubin

Mit einem benutzerdefinierten ==:

class A
  def ==(o)
    true
  end
end

a = A.new

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

Oder ein zunehmender a:

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

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

Python

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

Java

Es ist möglich, Java Integer cache zu ändern:

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.");
        }
    }
}
93
Eric Duminil

Dies ist eine umgekehrte Version von @ Jeffs Antwort *, wobei ein verstecktes Zeichen (U + 115F, U + 1160 oder U + 3164) zum Erstellen von Variablen verwendet wird, die wie 1, 2 und 3 aussehen.

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

* Diese Antwort kann vereinfacht werden, wenn Sie keinen Joiner mit Nullbreite (U + 200C) und einen Joiner mit Nullbreite (U + 200D) verwenden. Beide Zeichen sind in Bezeichnern erlaubt, jedoch nicht am Anfang:

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);
****/

Andere Tricks sind möglich, wenn dieselbe Idee verwendet wird, z. Verwenden Sie Unicode-Variationsselektoren, um Variablen zu erstellen, die genau gleich aussehen (a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

78
Salman A

Regel Nummer eins der Interviews; Sag niemals unmöglich.

Keine versteckten Charaktertrickereien nötig.

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?' );
}

72
MonkeyZeus

Aber ehrlich gesagt, ob es einen Weg gibt, um wahr zu sein oder nicht (und wie andere gezeigt haben, gibt es mehrere Möglichkeiten), wäre die Antwort, nach der ich suchen würde, so wie jemand, der Hunderte von Interviews geführt hat etwas in der Art von:

"Nun, vielleicht ja, unter einigen merkwürdigen Umständen, die mir nicht sofort klar sind ... aber wenn ich dies in echtem Code vorfinde, würde ich mit üblichen Debugging-Methoden herausfinden, wie und warum es das tat, was es tat und dann sofort den Code umgestalten, um diese Situation zu vermeiden ... aber noch wichtiger: Ich würde den Code NIEMALS an erster Stelle schreiben, da dies die Definition von gewundenem Code ist, und ich bemühe mich, niemals gewundenen Code zu schreiben. ".

Ich vermute, einige Interviewer würden sich offenbar mit einer offensichtlich sehr kniffligen Frage auseinandersetzen, aber Entwickler, die eine Meinung dazu haben, machen mir nichts aus, vor allem, wenn sie es mit begründeten Gedanken untermauern und meine Frage verzahnen können eine aussagekräftige Aussage über sich selbst.

66

Wenn Sie jemals eine solche Interviewfrage erhalten (oder ein gleichermaßen unerwartetes Verhalten in Ihrem Code bemerken), denken Sie darüber nach, welche Art von Dingen möglicherweise ein Verhalten hervorrufen könnten, das auf den ersten Blick unmöglich erscheint:

  1. Codierung : In diesem Fall ist die Variable, die Sie betrachten, nicht die, von der Sie glauben, dass sie es ist. Dies kann passieren, wenn Sie absichtlich mit Unicode herumspielen, indem Sie Homoglyphen oder Leerzeichen verwenden, um den Namen einer Variablen wie eine andere aussehen zu lassen, aber es können auch Codierungsprobleme auftreten versehentlich eingeführt werden, z beim Kopieren und Einfügen von Code aus dem Web, der unerwartete Unicode-Codepunkte enthält (z. B. weil ein Content-Management-System eine "automatische Formatierung" vorgenommen hat, z. B. indem fl durch Unicode "LATIN SMALL LIGATURE FL" ersetzt wurde (U + FB02) ).

  2. Rennbedingungen : Eine Rennbedingung kann auftreten, dh eine Situation, in der der Code nicht in der von erwarteten Reihenfolge ausgeführt wird der Entwickler. Race-Bedingungen treten häufig in Multithread-Code auf, aber mehrere Threads sind keine Voraussetzung, damit Race-Bedingungen möglich sind - Asynchronität ist ausreichend (und nicht zu verwechseln, Async bedeutet nicht, dass mehrere Threads unter der Haube verwendet werden ).

    Beachten Sie, dass JavaScript daher auch nicht frei von Race-Bedingungen ist, nur weil es Single-Threaded ist. Siehe hier für ein einfaches Single-Threaded-Beispiel - aber asynchron. Im Kontext einer einzelnen Aussage wäre die Racebedingung in JavaScript jedoch eher schwer zu treffen.

    JavaScript mit Webworkern ist etwas anders, da Sie mehrere Threads haben können. @mehulmpt hat uns einen großartigen Proof-of-Concept mit Webworkern gezeigt .

  3. Nebenwirkungen : Eine Nebenwirkung der Gleichstellungsvergleichsoperation (die nicht so offensichtlich sein muss wie in den Beispielen hier, häufig Effekte sind sehr subtil).

Diese Art von Problemen kann in vielen Programmiersprachen auftreten, nicht nur in JavaScript. Daher sehen wir hier keine der klassischen JavaScript WTFs1.

Natürlich sehen die Interviewfrage und die Beispiele hier alle sehr ausgefeilt aus. Aber sie sind eine gute Erinnerung daran, dass:

  • Nebenwirkungen können sehr unangenehm werden und ein gut gestaltetes Programm sollte frei von unerwünschten Nebenwirkungen sein.
  • Multithreading und veränderlicher Status können problematisch sein.
  • Wenn die Zeichenkodierung und die Verarbeitung von Zeichenfolgen nicht ordnungsgemäß ausgeführt werden, kann dies zu bösen Fehlern führen.

1 Zum Beispiel können Sie ein Beispiel in einer völlig anderen Programmiersprache (C #) finden, das einen Nebeneffekt aufweist (einen offensichtlichen) hier .

42
Dirk Vollmar

Hier ist eine weitere Variante: Verwenden Sie ein Array, um die gewünschten Werte abzurufen.

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

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

41
Théophile

Okay, ein weiterer Hack mit Generatoren:

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!');
}

31
BaggersIO

Die Antwort auf den ersten Teil der Frage lautet eigentlich "Ja" in jeder Programmiersprache. Dies ist beispielsweise im Fall von C/C++ der Fall:

#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

Proxies verwenden :

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

Proxies geben grundsätzlich vor, ein Zielobjekt (erster Parameter) zu sein, fangen jedoch Operationen am Zielobjekt ab (in diesem Fall die "get property" -Operation), sodass die Möglichkeit besteht, etwas anderes als das Standardobjektverhalten zu tun. In diesem Fall wird die Aktion "Eigenschaft abrufen" für a aufgerufen, wenn == seinen Typ erzwingt, um ihn mit jeder Zahl zu vergleichen. Das passiert:

  1. Wir erstellen ein Zielobjekt, { i: 0 }, wobei die i-Eigenschaft unser Zähler ist
  2. Wir erstellen einen Proxy für das Zielobjekt und weisen es a zu.
  3. Für jeden a ==-Vergleich wird der Typ von a zu einem primitiven Wert gezwungen
  4. Diese Art von Zwang führt zum internen Aufruf von a[Symbol.toPrimitive]()
  5. Der Proxy fängt ab, die a[Symbol.toPrimitive]-Funktion mithilfe des "get-Handlers" abzurufen.
  6. Der "get-Handler" des Proxys prüft, ob es sich bei der abgerufenen Eigenschaft um Symbol.toPrimitive handelt. In diesem Fall wird der Zähler vom Zielobjekt inkrementiert und zurückgegeben: ++target.i. Wenn eine andere Eigenschaft abgerufen wird, geben wir einfach den Standardeigenschaftswert zurück, target[name].

So:

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

Wie bei den meisten anderen Antworten funktioniert dies nur mit einer lockeren Gleichheitsprüfung (==), da strenge Gleichheitsüberprüfung (===) keinen Typzwang ausführt, den der Proxy abfangen kann.

27
IceCreamYou

Gleich, aber verschieden, aber immer noch gleich (kann mehrmals "getestet" werden):

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!');
}

Meine Idee ging davon aus, wie die Number-Objekttyp-Gleichung funktioniert.

26
Preda7or

Eine ECMAScript 6-Antwort, die Symbole verwendet:

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

Aufgrund der Verwendung von == soll JavaScript a in etwas nahe an den zweiten Operanden (1, 2, 3) umgewandelt werden. Bevor JavaScript jedoch versucht, den Zwang aus eigener Kraft herauszufinden, versucht es, Symbol.toPrimitive aufzurufen. Wenn Sie Symbol.toPrimitive angeben, würde JavaScript den Wert verwenden, den Ihre Funktion zurückgibt. Wenn nicht, würde JavaScript valueOf aufrufen.

23
Omar Alshaker

Ich denke, das ist der minimale Code, um es zu implementieren:

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

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

Erstellen eines Dummy-Objekts mit einer benutzerdefinierten valueOf, die bei jedem Aufruf eine globale Variable i inkrementiert. 23 Zeichen!

23
Gaafar

Dieser verwendet die defineProperty mit einem Nice-Nebeneffekt, der eine globale Variable verursacht!

var _a = 1

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

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

11
Ben Aubin

Durch Überschreiben von valueOf in einer Klassendeklaration können Sie Folgendes tun:

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

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

const a = new Thing();

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

Was passiert ist, dass valueOf in jedem Vergleichsoperator aufgerufen wird. Beim ersten wird a gleich 1 sein, beim zweiten wird a gleich 2 und so weiter und so fort, da bei jedem Aufruf von valueOf der Wert von a erhöht wird.

Daher wird das console.log ausgelöst und ausgegeben (in meinem Terminal sowieso) Thing: { value: 4}, um anzuzeigen, dass die Bedingung erfüllt ist.

0
Jonathan Kuhl