Anmerkung des Moderators: Bitte widersetzen Sie sich dem Drang, den Code zu bearbeiten oder diesen Hinweis zu entfernen. Das Leerzeichenmuster kann Teil der Frage sein und sollte daher nicht unnötig manipuliert werden. Wenn Sie sich im Lager "Leerzeichen sind unbedeutend" befinden, sollten Sie in der Lage sein, den Code unverändert zu akzeptieren.
Ist es jemals möglich, dass in JavaScript (a== 1 && a ==2 && a==3)
ausgewertet werden könnte true
?
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.
javascript
ecmascript-6
Dimpu Aravind Buddha
quelle
quelle
==
wenn Sie meinen===
, einen Codierungsstandard haben, der Nicht-ASCII-Variablennamen verbietet, und einen Flusenprozess, der die beiden vorherigen Moralvorstellungen durchsetzt.Antworten:
Wenn Sie nutzen , wie
==
funktioniert , könnten Sie einfach ein Objekt mit einer benutzerdefinierten erstellentoString
(odervalueOf
) Funktion , die ändert , was es jedes Mal wieder ist es so verwendet , dass es erfüllt alle drei Bedingungen.Der Grund, warum dies funktioniert, liegt in der Verwendung des Operators für lose Gleichheit. Wenn bei Verwendung der losen Gleichheit einer der Operanden von einem anderen Typ als der andere ist, versucht die Engine, einen in den anderen zu konvertieren. Bei einem Objekt auf der linken Seite und einer Nummer auf der rechten Seite wird versucht, das Objekt in eine Nummer umzuwandeln, indem zuerst
valueOf
aufgerufen wird , wenn es aufrufbar ist. Andernfalls wird es angerufentoString
. Ich habetoString
in diesem Fall einfach verwendet, weil es mir in den Sinn kamvalueOf
, sinnvoller wäre. Wenn ich stattdessen eine Zeichenfolge von zurückgegeben hättetoString
, hätte die Engine dann versucht, die Zeichenfolge in eine Zahl umzuwandeln, die das gleiche Endergebnis liefert, allerdings mit einem etwas längeren Pfad.quelle
valueOf()
Operation ändern ?valueOf
etwas besser.i
hat, stört die Engine nicht. ;)Ich konnte nicht widerstehen - die anderen Antworten sind zweifellos wahr, aber Sie können den folgenden Code wirklich nicht umgehen:
Beachten Sie den seltsamen Abstand in der
if
Anweisung (den ich von Ihrer Frage kopiert habe). Es ist das Hangul mit halber Breite (das ist Koreanisch für diejenigen, die nicht vertraut sind), 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 unterschiedliche Variablen, eine mit dem Hangul nach dem a, eine mit dem vor und die letzte mit nur einem. Wenn Sie den Speicherplatz_
aus Gründen der Lesbarkeit durch ersetzen , sieht derselbe Code folgendermaßen aus:Überprüfen Sie die Validierung auf Mathias 'Variablennamen-Validator . Wenn dieser seltsame Abstand tatsächlich in ihrer Frage enthalten war, bin ich mir sicher, dass dies ein Hinweis für diese Art von Antwort ist.
Tu das nicht. Ernsthaft.
Bearbeiten: Es ist mir aufgefallen, dass (obwohl es nicht erlaubt ist, eine Variable zu starten) die Joiner- Zeichen mit der Breite Null und die Nicht-Joiner- Zeichen mit der Breite Null auch in Variablennamen zulässig sind - siehe Verschleierung von JavaScript mit Zeichen mit der Breite Null - Vor- und Nachteile ? .
Dies würde wie folgt aussehen:
quelle
var ᅠ2 = 3
verwendet. Also gibt es die drei Variablenaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
, damit(a␣==1 && a==␣2 && a==3)
)…ES IST MÖGLICH!
Dies verwendet einen Getter innerhalb einer
with
Anweisung, uma
drei verschiedene Werte auswerten zu lassen .... das bedeutet immer noch nicht, dass dies in echtem Code verwendet werden sollte ...
Schlimmer noch, dieser Trick funktioniert auch mit der Verwendung von
===
.quelle
with
."with
das nicht erlaubt ist.with
damit es passieren kann==
. Und===
verhindert die akzeptierte Antwort==
aber ich habe eswith
seitdem nicht mehr gesehen ... naja, eigentlich nie außerhalb der JS-Dokumentation, wo es heißt "Bitte benutze das nicht". Wie auch immer, eine schöne Lösung.Beispiel ohne Getter oder valueOf:
Dies funktioniert , weil
==
aufruft ,toString
die Anrufe.join
für Arrays.Eine andere Lösung, bei
Symbol.toPrimitive
der es sich um ein ES6-Äquivalent handelt vontoString/valueOf
:quelle
without valueOf
Nun, es ist indirekter, aber im Grunde das Gleiche.toString
odervalueOf
aber dies erwischte mich völlig aus der Wache. Sehr klug und ich wusste nicht, dass es.join
intern angerufen wurde , aber es macht total Sinn.Wenn gefragt wird, ob dies möglich ist (nicht MUSS), kann "a" aufgefordert werden, eine Zufallszahl zurückzugeben. Es wäre wahr, wenn es nacheinander 1, 2 und 3 erzeugen würde.
quelle
Wenn Sie ohne reguläre Ausdrücke nichts tun können:
Dies funktioniert aufgrund einer benutzerdefinierten
valueOf
Methode, die aufgerufen wird, wenn Object mit primitiv verglichen wird (z. B. Number). Der Haupttrick besteht darin, dassa.valueOf
jedes Mal ein neuer Wert zurückgegeben wird, da einexec
regulärer Ausdruck mitg
Flag aufgerufen wird, wodurchlastIndex
dieser reguläre Ausdruck jedes Mal aktualisiert wird , wenn eine Übereinstimmung gefunden wird. Beim ersten Malthis.r.lastIndex == 0
stimmt es überein1
und wird aktualisiertlastIndex
: Beimthis.r.lastIndex == 1
nächsten Mal stimmt der reguläre Ausdruck überein2
und so weiter.quelle
exec
erneuter Aufruf beginnt mit der Suche von diesem Index aus. MDN ist nicht sehr klar.this.r
verstehe , also erinnert sich das Regex-Objekt an den Status / Index. Vielen Dank!exec
, nicht eine zu stringifizierende Ganzzahl.Dies kann im globalen Bereich wie folgt erreicht werden. Zur
nodejs
Verwendungglobal
anstelle des folgendenwindow
Codes.Diese Antwort missbraucht die impliziten Variablen, die vom globalen Bereich im Ausführungskontext bereitgestellt werden, indem ein Getter zum Abrufen der Variablen definiert wird.
quelle
a
es sich um eine Eigenschaft handelt,this
die es nicht zu sein scheint. Wenna
es sich um eine lokale Variable handelt (wie sie aussieht), würde dies nicht funktionieren.a == 1
impliziert, dassa
es sich irgendwo um eine Variable handelt, nicht um eine Eigenschaft vonthis
. Während es einen seltsamen Ort wie Globals gibt, an dem beides wahr sein könnte, bedeutet das Deklarieren einer Variablen mitvar a
oderlet a
bedeutet, dass es keine gibtthis
, auf die Siea
als Eigenschaft zugreifen können, wie Sie es von Code annehmen. Ihr Code geht also anscheinend von einer seltsamen globalen Variablen aus. Beispielsweise funktioniert Ihr Code nicht in node.js und nicht im strengen Modus innerhalb einer Funktion. Sie sollten die genauen Umstände angeben, unter denen es funktioniert, und wahrscheinlich erklären, warum es funktioniert. Ansonsten ist es irreführend.a
handelt sich nicht um eine lokale Variable und wird im globalen Bereich mit einem inkrementierenden Getter definiert.Dies ist möglich, wenn auf Variablen
a
von beispielsweise 2 Web-Workern über einen SharedArrayBuffer sowie ein Hauptskript zugegriffen wird. Die Möglichkeit ist gering, aber es ist möglich , dass , wenn der Code in Maschinencode kompiliert wird, die Web - Arbeiter die Variable aktualisieren ,a
so dass die Bedingungen gerade rechtzeitiga==1
,a==2
unda==3
sind zufrieden.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
worker.js
modifier.js
Auf meinem MacBook Air geschieht dies nach ungefähr 10 Milliarden Iterationen beim ersten Versuch:
Zweiter Versuch:
Wie gesagt, die Chancen werden gering sein, aber wenn genügend Zeit zur Verfügung steht, wird es die Bedingung treffen.
Tipp: Wenn es auf Ihrem System zu lange dauert. Versuchen Sie es nur
a == 1 && a == 2
und wechseln SieMath.random()*3
zuMath.random()*2
. Wenn Sie mehr und mehr zur Liste hinzufügen, verringert sich die Trefferchance.quelle
Dies ist auch mit einer Reihe von selbst überschreibenden Gettern möglich:
(Dies ähnelt der Lösung von jontro, erfordert jedoch keine Zählervariable.)
quelle
===
nicht nur funktioniert==
.this
, das globale Objekt innerhalb des Körpers der Pfeilfunktion zu sein.(a == 3 && a == 2 && a == 1)
?Alternativ können Sie eine Klasse dafür und eine Instanz für die Prüfung verwenden.
BEARBEITEN
Mit ES6-Klassen würde es so aussehen
quelle
function A() {value = 0;
am Anfang?valueOf
wird überschrieben,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
also wenn wir den Wert vergleichen, erhöht er tatsächlich a ..Ich sehe diese Antwort nicht bereits gepostet, also werde ich diese auch in die Mischung werfen. Dies ähnelt Jeffs Antwort mit dem Hangul-Raum halber Breite.
Möglicherweise stellen Sie eine leichte Abweichung von der zweiten fest, aber die erste und dritte sind mit dem bloßen Auge identisch. Alle 3 sind unterschiedliche Zeichen:
a
- Lateinische Kleinbuchstaben Aa
- Volle Breite Lateinische Kleinbuchstaben Aа
- Kyrillische Kleinbuchstaben A.Der Oberbegriff dafür ist "Homoglyphen": verschiedene Unicode-Zeichen, die gleich aussehen. Normalerweise ist es schwierig, drei zu bekommen , die absolut nicht zu unterscheiden sind, aber in einigen Fällen kann man Glück haben. A, Α, А und Ꭺ würde besser funktionieren (Latein-A, griechisches Alpha , Kyrillisch-A und Cherokee-A verbunden sind; leider die griechische und Cherokee Kleinbuchstaben sind zu verschieden von dem lateinischen
a
:α
,ꭺ
und so doesn Ich helfe nicht mit dem obigen Ausschnitt.Es gibt eine ganze Klasse von Homoglyphenangriffen, am häufigsten in gefälschten Domainnamen (z. B.
wikipediа.org
(kyrillisch) vswikipedia.org
(lateinisch)), aber sie können auch im Code angezeigt werden . Wird normalerweise als hinterhältig bezeichnet (wie in einem Kommentar erwähnt, sind [hinterhältige] Fragen bei PPCG nicht mehr aktuell , waren jedoch früher eine Art Herausforderung, bei der sich solche Dinge zeigten). Ich habe diese Website verwendet , um die für diese Antwort verwendeten Homoglyphen zu finden.quelle
a
:a︀
a︁
a︂
. Machen Sie sich keine Sorgen mehr über Unstimmigkeiten.Ja, es ist möglich! 😎
»JavaScript
Der obige Code ist eine Kurzversion (danke an @Forivin für den Hinweis in den Kommentaren) und der folgende Code ist original:
» C #
Außerdem habe ich eine C # -Version geschrieben ( mit Technik zur Erhöhung des Eigenschaftswerts ):
Live-Demo
quelle
if=()=>!0
document.write
? Das ist ein todsicherer Weg, um unabhängig vom Rest der Antwort nicht eingestellt zu werden.console.log
aber ich habe sie in document.write geändert. Wirklich immer verwende ichconsole.log
in meinen Codes, aber hier möchte ich den Benutzern nur einen Text im StackOverflow-Code-Snippet-Feld anzeigen. Deshalb wollte ich meine Nachricht schöner zeigen als die vonconsole.log
. Klicken Sie auf dieRun Code Snippet
Schaltfläche in meiner Antwort und auf andere Antworten. Mit dem SO-Code-Snippet konnte ich HTML, JS und CSS verwenden, dann wollte ich es in meiner Antwort verwenden und es schön machen. Ich denke, es hat keine negativen Nebenwirkungen und hat meine Antwort nicht groß oder vollständig gemacht.JavaScript
a == a +1
In JavaScript gibt es keine Ganzzahlen, sondern nur
Number
s, die als Gleitkommazahlen mit doppelter Genauigkeit implementiert sind.Dies bedeutet, dass eine Zahl,
a
die groß genug ist, als gleich drei aufeinanderfolgende Ganzzahlen betrachtet werden kann:Es ist zwar nicht genau das, was der Interviewer gefragt hat (es funktioniert nicht damit
a=0
), aber es beinhaltet keinen Trick mit versteckten Funktionen oder Überlastung des Bedieners.Andere Sprachen
Als Referenz gibt es
a==1 && a==2 && a==3
Lösungen in Ruby und Python. Mit einer geringfügigen Änderung ist dies auch in Java möglich.Rubin
Mit einem Brauch
==
:Oder eine zunehmende
a
:Python
Java
Es ist möglich, den Java-
Integer
Cache zu ändern :quelle
Integer a = 42
(oder funktioniert es)? Soweit ich Autoboxing verstehe,Integer a = 42; a == 1 && a == 2 && a == 3
sollten alle Ints verpackt werden. Oder entpackt dies eine für die Vergleiche?Integer == int
scheint zu Unboxing zu führen. Aber mitInteger#equals(int)
Force Autoboxing, so funktioniert es. Danke für den Kommentar!Numbers
in JS, die im Grunde wiedouble
s sind. Sie können wie Ganzzahlen aussehen und Sie können sie wie Ganzzahlen verwenden, aber sie sind immer noch keine Ganzzahlen. Ich glaube nicht, dassn == n + 1
dies jemals für ganze Zahlen in Java / Python / C / Ruby / ... zutreffen kannDies ist eine invertierte Version von @ Jeffs Antwort * wo ein verstecktes Zeichen (U + 115F, U + 1160 oder U + 3164) verwendet wird , Variablen zu erstellen , die aussehen wie
1
,2
und3
.* Diese Antwort kann vereinfacht werden, indem ein Nicht-Joiner mit Nullbreite (U + 200C) und ein Joiner mit Nullbreite (U + 200D) verwendet werden. Diese beiden Zeichen sind in Bezeichnern zulässig, jedoch nicht am Anfang:
Andere Tricks sind mit derselben Idee möglich, z. B. mithilfe von Unicode-Variationsselektoren, um Variablen zu erstellen, die genau gleich aussehen (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).quelle
Regel Nummer eins der Interviews; Sag niemals unmöglich.
Keine Notwendigkeit für Tricks mit versteckten Charakteren.
quelle
__defineGetter__
ist eigentlich nicht Teil der js-Sprache, nur eine hässliche Version vondefineProperty
.typeof
ist keine Funktion und diese nicht deklariertei
ist einfach schrecklich. Scheint immer noch 40 Upvotes wert zu sein: /__defineGetter__
pro Entwickler nicht mehr empfohlen wirddefineProperty()
weil Legacy-Code echt ist und nicht ignoriert werden kann. Unabhängig von der Hässlichkeiti
ist es ein bekanntes / dokumentiertes Verhalten , so zu erklären, wie ich es getan habe. Vielleicht war ich nur in einer PCG-Stimmung ¯ \ _ (ツ) _ / ¯Ehrlich gesagt, ob es eine Möglichkeit gibt, sie als wahr zu bewerten oder nicht (und wie andere gezeigt haben, gibt es mehrere Möglichkeiten), wäre die Antwort, nach der ich suchen würde, wenn ich als jemand spreche, der Hunderte von Interviews geführt hat etwas in der Art von:
"Nun, vielleicht ja unter einigen seltsamen Umständen, die mir nicht sofort klar sind ... aber wenn ich dies in echtem Code antreffen würde, würde ich gängige Debugging-Techniken verwenden, um herauszufinden, wie und warum es das tat, was es tat und dann den Code sofort umgestalten, um diese Situation zu vermeiden ... aber was noch wichtiger ist: Ich würde diesen Code NIEMALS schreiben, da dies genau die Definition von verschlungenem Code ist und ich mich bemühe, niemals verschlungenen Code zu schreiben. "
Ich denke, einige Interviewer würden es beleidigen, wenn eine offensichtlich sehr knifflige Frage gestellt wird, aber es macht mir nichts aus, wenn Entwickler eine Meinung haben, insbesondere wenn sie diese mit begründeten Gedanken untermauern und meine Frage ineinander greifen können eine aussagekräftige Aussage über sich.
quelle
Wenn Sie jemals eine solche Interviewfrage erhalten (oder ein ebenso unerwartetes Verhalten in Ihrem Code bemerken), überlegen Sie, welche Art von Dingen möglicherweise ein Verhalten verursachen können, das auf den ersten Blick unmöglich erscheint:
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 , damit der Name einer Variablen wie eine andere aussieht. Codierungsprobleme können jedoch auch versehentlich auftreten, z. B. beim Kopieren und Einfügen von Code aus dem Web, der unerwarteten Unicode-Code enthält Punkte (z. B. weil ein Content-Management-System einige "automatische Formatierungen" vorgenommen hat, z. B. das Ersetzen
fl
durch Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).Rennbedingungen : Eine Rennbedingung kann auftreten, dh eine Situation, in der Code nicht in der vom Entwickler erwarteten Reihenfolge ausgeführt wird. Race-Bedingungen treten häufig in Multithread-Code auf, aber mehrere Threads sind keine Voraussetzung dafür, dass 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 Rennbedingungen ist, nur weil es Single-Threaded ist. Sehen Sie hier für ein einfaches Single-Threaded - aber Asynchron - Beispiel. Im Kontext einer einzelnen Aussage wäre die Rennbedingung in JavaScript jedoch ziemlich schwer zu treffen.
JavaScript mit Web-Workern ist etwas anders, da Sie mehrere Threads haben können. @mehulmpt hat uns einen großartigen Proof-of-Concept mit Web- Workern gezeigt .
Nebenwirkungen : Eine Nebenwirkung der Gleichheitsvergleichsoperation (die nicht so offensichtlich sein muss wie in den Beispielen hier, häufig sind Nebenwirkungen sehr subtil).
Diese Art von Fragen können in vielen Programmiersprachen erscheinen, nicht nur JavaScript, so dass wir nicht zu den klassischen Sehen Sie JavaScript WTFs hier 1 .
Natürlich sehen die Interviewfrage und die Beispiele hier alle sehr ausgefeilt aus. Aber sie sind eine gute Erinnerung daran, dass:
1 Zum Beispiel können Sie ein Beispiel in einer völlig anderen Programmiersprache (C #) aufweist , eine Nebenwirkung (eine der nahe liegenden) finden sich hier .
quelle
Hier ist eine weitere Variante, bei der mithilfe eines Arrays beliebige Werte angezeigt werden.
quelle
Okay, noch ein Hack mit Generatoren:
quelle
this
, das Fensterobjekt zu sein)Mit Proxies :
Proxies geben im Grunde genommen vor, ein Zielobjekt zu sein (der erste Parameter), fangen jedoch Operationen am Zielobjekt ab (in diesem Fall die Operation "get property"), sodass die Möglichkeit besteht, etwas anderes als das Standardobjektverhalten auszuführen. In diesem Fall wird die Aktion "get property" aufgerufen,
a
wenn==
der Typ erzwungen wird, um ihn mit jeder Zahl zu vergleichen. Das passiert:{ i: 0 }
in dem diei
Eigenschaft unser Zähler ista
a ==
Vergleich wirda
der Typ auf einen primitiven Wert gezwungena[Symbol.toPrimitive]()
internen Anrufa[Symbol.toPrimitive]
Funktion mit dem "get handler" abzurufen.Symbol.toPrimitive
. In diesem Fall erhöht er den Zähler und gibt ihn vom Zielobjekt zurück :++target.i
. Wenn eine andere Eigenschaft abgerufen wird, wird einfach auf den Standardeigenschaftswert zurückgegriffen.target[name]
Damit:
Wie bei den meisten anderen Antworten funktioniert dies nur mit einer losen Gleichheitsprüfung (
==
), da strenge Gleichheitsprüfungen (===
) keinen Typzwang ausüben, den der Proxy abfangen kann.quelle
Symbol.toPrimitive
die gleiche Definition für ein Objekt würde genauso gut funktionieren.Tatsächlich lautet die Antwort auf den ersten Teil der Frage in jeder Programmiersprache "Ja". Dies ist beispielsweise bei C / C ++ der Fall:
quelle
&&
für logisches "und" verwendet.Gleich, aber unterschiedlich, aber immer noch gleich (kann mehrfach "getestet" werden):
Meine Idee begann damit, wie die Gleichung des Zahlenobjekttyps funktioniert.
quelle
Eine ECMAScript 6-Antwort, die Symbole verwendet:
Durch
==
Nutzung wird JavaScript soll coercea
in etwas nahe dem zweiten Operanden (1
,2
,3
in diesem Fall). Bevor JavaScript jedoch versucht, das Erzwingen selbst zu ermitteln, wird versucht, es aufzurufenSymbol.toPrimitive
. Wenn SieSymbol.toPrimitive
JavaScript bereitstellen , wird der Wert verwendet, den Ihre Funktion zurückgibt. Wenn nicht, würde JavaScript aufrufenvalueOf
.quelle
Ich denke, dies ist der minimale Code, um es zu implementieren:
Erstellen eines Dummy-Objekts mit einem benutzerdefinierten Objekt, das bei jedem Aufruf
valueOf
eine globale Variable erhöhti
. 23 Zeichen!quelle
Dieser verwendet die defineProperty mit einem netten Nebeneffekt, der eine globale Variable verursacht!
quelle
a
:get: (a => () => ++a)(0),
kein globales notwendig.Durch Überschreiben
valueOf
einer Klassendeklaration kann Folgendes erreicht werden:Was passiert, ist, dass
valueOf
in jedem Vergleichsoperator aufgerufen wird. Auf dem erstena
wird gleich sein1
, auf dem zweitena
wird gleich sein2
, und so weiter und so fort, weil jedes MalvalueOf
, wenn aufgerufen wird, der Wert vona
erhöht wird.Daher wird die console.log ausgelöst und ausgegeben (jedenfalls in meinem Terminal)
Thing: { value: 4}
, was darauf hinweist , dass die Bedingung wahr ist.quelle