Note du modérateur: veuillez résister à l'envie de modifier le code ou de supprimer cet avis. Le motif des espaces blancs peut faire partie de la question et ne doit donc pas être altéré inutilement. Si vous êtes dans le camp "les espaces blancs sont insignifiants", vous devriez pouvoir accepter le code tel quel.
Est-il possible que cela (a== 1 && a ==2 && a==3)
puisse être évalué true
en JavaScript?
Il s'agit d'une question d'entrevue posée par une grande entreprise de technologie. C'est arrivé il y a deux semaines, mais j'essaie toujours de trouver la réponse. Je sais que nous n'écrivons jamais un tel code dans notre travail quotidien, mais je suis curieux.
javascript
ecmascript-6
Dimpu Aravind Buddha
la source
la source
==
quand vous voulez dire===
, avoir une norme de codage qui interdit les noms de variables non ASCII et avoir un processus de peluchage qui applique les deux mœurs précédentes.Réponses:
Si vous profitez de la façon dont
==
fonctionne , vous pouvez simplement créer un objet avec une fonction personnaliséetoString
(ouvalueOf
) qui change ce qu'il retourne chaque fois qu'il est utilisé de telle sorte qu'il remplit les trois conditions.La raison pour laquelle cela fonctionne est due à l'utilisation de l'opérateur d'égalité lâche. Lors de l'utilisation d'une égalité lâche, si l'un des opérandes est d'un type différent de l'autre, le moteur tentera de convertir l'un en l'autre. Dans le cas d'un objet à gauche et d'un numéro à droite, il tentera de convertir l'objet en un numéro en appelant d'abord
valueOf
s'il est appelable, et à défaut, il appelleratoString
. J'ai utilisétoString
dans ce cas simplement parce que c'est ce qui m'est venu à l'esprit,valueOf
aurait plus de sens. Si j'avais plutôt renvoyé une chaînetoString
, le moteur aurait alors tenté de convertir la chaîne en un nombre nous donnant le même résultat final, mais avec un chemin légèrement plus long.la source
valueOf()
opération implicite ?valueOf
c'est légèrement mieux.i
ne dérange pas le moteur. ;)Je n'ai pas pu résister - les autres réponses sont sans aucun doute vraies, mais vous ne pouvez vraiment pas passer devant le code suivant:
Notez l'espacement étrange dans la
if
déclaration (que j'ai copiée de votre question). C'est le Hangul demi-largeur (qui est coréen pour ceux qui ne sont pas familiers) qui est un caractère d'espace Unicode qui n'est pas interprété par le script ECMA comme un caractère d'espace - cela signifie qu'il s'agit d'un caractère valide pour un identifiant. Il y a donc trois variables complètement différentes, une avec le Hangul après le a, une avec lui avant et la dernière avec juste un. En remplaçant l'espace par_
lisibilité, le même code ressemblerait à ceci:Découvrez la validation sur le validateur de nom de variable de Mathias . Si cet espacement étrange était réellement inclus dans leur question, je suis sûr que c'est un indice pour ce genre de réponse.
Ne fais pas ça. Sérieusement.
Edit: Il est venu à mon attention que (bien qu'il ne soit pas autorisé à démarrer une variable) le menuisier de largeur nulle et de non-jointure de largeur nulle sont également autorisés dans les noms de variables - voir Obfuscation de JavaScript avec des caractères de largeur nulle - avantages et inconvénients ? .
Cela ressemblerait à ceci:
la source
var ᅠ2 = 3
a été utilisée; donc il y a les trois variablesaᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
, pour que(a␣==1 && a==␣2 && a==3)
)…C'EST POSSIBLE!
Cela utilise un getter à l'intérieur d'une
with
instruction pour permettre d'a
évaluer trois valeurs différentes.... cela ne signifie toujours pas que cela devrait être utilisé dans du vrai code ...
Pire encore, cette astuce fonctionnera également avec l'utilisation de
===
.la source
with
."with
n'est pas autorisé.with
que cela puisse arriver==
. Et===
empêche la réponse acceptée==
mais je n'ai pas vuwith
depuis ... enfin en fait jamais en dehors de la documentation JS où il est dit "veuillez ne pas utiliser cela". Quoi qu'il en soit, une belle solution.Exemple sans getters ou valueOf:
Cela fonctionne car
==
invoquetoString
qui appelle.join
des tableaux.Une autre solution, utilisant
Symbol.toPrimitive
qui est un équivalent ES6 detoString/valueOf
:la source
without valueOf
, eh bien ... c'est plus indirect mais essentiellement la même chose.toString
ou,valueOf
mais celle-ci m'a complètement pris au dépourvu. Très intelligent et je ne savais pas qu'il appelait en.join
interne, mais c'est tout à fait logique.Si on lui demande si c'est possible (pas DOIT), il peut demander à "a" de retourner un nombre aléatoire. Ce serait vrai s'il génère 1, 2 et 3 séquentiellement.
la source
Lorsque vous ne pouvez rien faire sans expressions régulières:
Il fonctionne en raison de la
valueOf
méthode personnalisée qui est appelée lorsque Object est comparé à une primitive (telle que Number). L'astuce principale est dea.valueOf
renvoyer une nouvelle valeur à chaque fois car elle appelleexec
une expression régulière avecg
indicateur, ce qui provoque la mise à jourlastIndex
de cette expression régulière à chaque fois qu'une correspondance est trouvée. Donc , première foisthis.r.lastIndex == 0
, il correspond1
et mises à jourlastIndex
:this.r.lastIndex == 1
, donc la prochaine fois regex correspondra2
et ainsi de suite.la source
exec
nouveau commencera la recherche à partir de cet index. MDN n'est pas très clair.this.r
objet regex se souvient de l'état / index. Merci!exec
, pas un entier à stringifier.Cela peut être accompli en utilisant ce qui suit dans la portée globale. À
nodejs
utiliserglobal
au lieu dewindow
dans le code ci-dessous.Cette réponse abuse des variables implicites fournies par la portée globale dans le contexte d'exécution en définissant un getter pour récupérer la variable.
la source
a
c'est une propriététhis
dont il ne semble pas être. S'ila
s'agissait d'une variable locale (à laquelle elle ressemble), cela ne fonctionnerait pas.a == 1
implique qu'unea
variable est quelque part, et non une propriété dethis
. Bien qu'il existe un endroit étrange comme les globaux où les deux pourraient être vrais, généralement, déclarer une variable avecvar a
oulet a
signifie qu'il n'y a pas dethis
qui vous permet d'accéder ena
tant que propriété comme le suppose votre code. Donc, votre code suppose apparemment quelque chose de variable globale bizarre. Par exemple, votre code ne fonctionne pas dans node.js et pas en mode strict dans une fonction. Vous devez spécifier les circonstances exactes où cela fonctionne et probablement expliquer pourquoi cela fonctionne. Sinon, c'est trompeur.a
n'est pas une variable locale et est défini sur la portée globale avec un getter incrémentiel.Ceci est possible en cas d'
a
accès à une variable par, disons, 2 travailleurs Web via un SharedArrayBuffer ainsi que certains scripts principaux. La possibilité est faible, mais il est possible que lorsque le code est compilé en code machine, les travailleurs Web mettent à jour la variablea
juste à temps pour que les conditionsa==1
,a==2
eta==3
sont satisfaits.Cela peut être un exemple de condition de concurrence critique dans un environnement multithread fourni par les travailleurs Web et SharedArrayBuffer en JavaScript.
Voici l'implémentation de base de ci-dessus:
main.js
travailleur.js
modifier.js
Sur mon MacBook Air, cela se produit après environ 10 milliards d'itérations lors de la première tentative:
Deuxième essai:
Comme je l'ai dit, les chances seront faibles, mais avec suffisamment de temps, cela atteindra la situation.
Astuce: si cela prend trop de temps sur votre système. Essayez uniquement
a == 1 && a == 2
et passezMath.random()*3
àMath.random()*2
. Ajouter de plus en plus à la liste diminue les chances de frapper.la source
Ceci est également possible en utilisant une série de getters auto-écrasants:
(Ceci est similaire à la solution de jontro, mais ne nécessite pas de variable de compteur.)
la source
===
, pas seulement==
.this
être l'objet global à l'intérieur du corps de la fonction flèche.(a == 3 && a == 2 && a == 1)
,?Alternativement, vous pouvez utiliser une classe pour elle et une instance pour la vérification.
ÉDITER
En utilisant les classes ES6, cela ressemblerait à ceci
la source
function A() {value = 0;
au début?valueOf
est remplacé,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
donc quand on compare la valeur, il incrémente en fait un ..Je ne vois pas cette réponse déjà publiée, donc je vais jeter celle-ci dans le mélange aussi. Ceci est similaire à la réponse de Jeff avec l'espace Hangul demi-largeur.
Vous remarquerez peut-être un léger écart avec le second, mais le premier et le troisième sont identiques à l'œil nu. Les 3 sont des caractères distincts:
a
- Minuscules latines Aa
- Minuscules latines pleine largeur Aа
- Minuscules cyrilliques ALe terme générique pour cela est "homoglyphes": différents caractères unicode qui se ressemblent. Il est généralement difficile d'en obtenir trois qui sont totalement indiscernables, mais dans certains cas, vous pouvez avoir de la chance. A, Α, А et Ꭺ fonctionneraient mieux (latin-A, grec alpha , cyrillique-A et Cherokee-A respectivement, malheureusement , le grec et Cherokee lettres minuscules sont trop différents du latin
a
:α
,ꭺ
, et ainsi doesn 't aider avec l'extrait ci-dessus).Il existe toute une classe d'attaques d'homoglyphes, le plus souvent dans de faux noms de domaine (par exemple
wikipediа.org
(cyrillique) vswikipedia.org
(latin)), mais il peut également apparaître dans le code; généralement dénommé sournois (comme mentionné dans un commentaire, les questions [sournoises] sont désormais hors sujet sur PPCG , mais étaient un type de défi où ce genre de choses apparaissait). j'ai utilisé ce site Web pour trouver les homoglyphes utilisés pour cette réponse.la source
a
:a︀
a︁
a︂
. Ne vous inquiétez plus des écarts.Oui c'est possible! 😎
»JavaScript
Le code ci-dessus est une version courte (merci à @Forivin pour sa note dans les commentaires) et le code suivant est original:
» C #
J'ai également écrit une version C # ( avec une technique d'augmentation de la valeur des propriétés ):
Démo en direct
la source
if=()=>!0
document.write
? C'est un moyen infaillible de ne pas être embauché, peu importe le reste de la réponse.console.log
mais je l'ai changé en document.write. Je l'utilise vraiment toujoursconsole.log
dans mes codes, mais ici, je veux juste montrer un texte aux utilisateurs dans la zone d'extrait de code StackOverflow. Je voulais donc montrer mon message plus beau que le message généré parconsole.log
. Cliquez sur leRun Code Snippet
bouton sur ma réponse et sur d'autres réponses. L'extrait de code SO m'a permis d'utiliser html et JS et CSS, puis j'ai voulu l'utiliser dans ma réponse et le rendre agréable. Je pense que cela n'a aucun effet secondaire négatif et n'a pas rendu ma réponse grande ou compliquée.Javascript
a == a +1
En JavaScript, il n'y a pas d' entiers mais seulement des
Number
s, qui sont implémentés comme des nombres à virgule flottante double précision.Cela signifie que si un nombre
a
est suffisamment grand, il peut être considéré comme égal à trois entiers consécutifs:Certes, ce n'est pas exactement ce que l'intervieweur a demandé (cela ne fonctionne pas
a=0
), mais cela n'implique aucune astuce avec des fonctions cachées ou une surcharge d'opérateur.Autres langues
Pour référence, il existe des
a==1 && a==2 && a==3
solutions en Ruby et Python. Avec une légère modification, c'est également possible en Java.Rubis
Avec une coutume
==
:Ou une augmentation
a
:Python
Java
Il est possible de modifier le
Integer
cache Java :la source
Integer a = 42
(ou fonctionne-t-elle)? Si je comprends bien laInteger a = 42; a == 1 && a == 2 && a == 3
boîte automatique, devrait encadrer toutes les entrées. Ou cela déballe-t-il un pour les comparaisons?Integer == int
semble entraîner le déballage. Mais en utilisant lesInteger#equals(int)
forces de l'autoboxing, cela fonctionne. Merci pour le commentaire!Numbers
dans JS, qui sont essentiellement comme l'double
art. Ils peuvent ressembler à des entiers et vous pouvez les utiliser comme des entiers, mais ce ne sont toujours pas des entiers. Je ne pense pas que celan == n + 1
puisse jamais être vrai pour les entiers en Java / Python / C / Ruby / ...Il s'agit d'une version inversée de la réponse de @ Jeff * où un caractère caché (U + 115F, U + 1160 ou U + 3164) est utilisé pour créer des variables qui ressemblent à
1
,2
et3
.* Cette réponse peut être simplifiée en utilisant un non-jointeur de largeur nulle (U + 200C) et un jointeur de largeur nulle (U + 200D). Ces deux caractères sont autorisés à l'intérieur des identifiants mais pas au début:
D'autres astuces sont possibles en utilisant la même idée, par exemple en utilisant des sélecteurs de variation Unicode pour créer des variables qui se ressemblent exactement (
a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
).la source
Règle numéro un des entretiens; ne dites jamais impossible.
Pas besoin de tromperie de personnage caché.
la source
__defineGetter__
ne fait en fait pas partie du langage js, juste une version laide dedefineProperty
.typeof
n'est pas une fonction et ce non déclaréi
est tout simplement horrible. Semble toujours valoir 40 votes positifs: /__defineGetter__
c'est déprécié par developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… mais il s'exécute clairement dans mon FireFox v 57.0.4, j'ai donc choisi de l'afficher au lieu dedefineProperty()
car le code hérité est réel et ne peut être ignoré. Indépendamment de la laideur, déclareri
comme je l'ai fait est un comportement bien connu / documenté. Peut-être que j'étais juste d'humeur PCG ¯ \ _ (ツ) _ / ¯Honnêtement cependant, qu'il existe un moyen d'évaluer cela comme vrai ou non (et comme d'autres l'ont montré, il existe plusieurs façons), la réponse que je chercherais, parlant comme quelqu'un qui a mené des centaines d'interviews, serait quelque chose comme:
"Eh bien, peut-être que oui dans un ensemble de circonstances étranges qui ne sont pas immédiatement évidentes pour moi ... mais si je rencontrais cela dans du vrai code, j'utiliserais des techniques de débogage communes pour comprendre comment et pourquoi il faisait ce qu'il faisait puis refactoriser immédiatement le code pour éviter cette situation ... mais plus important encore: je n'écrirais JAMAIS absolument ce code en premier lieu parce que c'est la définition même du code alambiqué, et je m'efforce de ne jamais écrire du code alambiqué ".
Je suppose que certains intervieweurs seraient offensés de voir ce qui est manifestement censé être une question très délicate, mais cela ne me dérange pas des développeurs qui ont une opinion, surtout quand ils peuvent l'étayer avec une pensée raisonnée et peuvent concilier ma question une déclaration significative sur eux-mêmes.
la source
Si jamais vous obtenez une telle question d'entrevue (ou remarquez un comportement tout aussi inattendu dans votre code) pensez à quel genre de choses pourrait éventuellement provoquer un comportement qui semble impossible à première vue:
Encodage : dans ce cas, la variable que vous regardez n'est pas celle que vous pensez qu'elle est. Cela peut se produire si vous vous trompez intentionnellement avec Unicode en utilisant des homoglyphes ou des caractères d'espacement pour faire ressembler le nom d'une variable à une autre, mais des problèmes d'encodage peuvent également être introduits accidentellement, par exemple lors de la copie et du collage de code à partir du Web qui contient du code Unicode inattendu (par exemple parce qu'un système de gestion de contenu a fait un "formatage automatique" tel que le remplacement
fl
par Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).Conditions de concurrence : Une condition de concurrence peut se produire, c'est-à-dire une situation où le code ne s'exécute pas dans la séquence attendue par le développeur. Les conditions de concurrence se produisent souvent dans le code multi-thread, mais plusieurs threads ne sont pas nécessaires pour que les conditions de concurrence soient possibles - l'asynchronicité est suffisante (et ne vous trompez pas , async ne signifie pas que plusieurs threads sont utilisés sous le capot ).
Notez que par conséquent, JavaScript n'est pas non plus exempt de conditions de concurrence simplement parce qu'il est monothread. Voir ici pour un exemple simple à un seul thread - mais asynchrone. Dans le contexte d'une seule déclaration, la condition de concurrence serait cependant assez difficile à atteindre en JavaScript.
JavaScript avec les travailleurs Web est un peu différent, car vous pouvez avoir plusieurs threads. @mehulmpt nous a montré une excellente preuve de concept en utilisant des travailleurs Web .
Effets secondaires : Un effet secondaire de l'opération de comparaison d'égalité (qui ne doit pas être aussi évident que dans les exemples ici, souvent les effets secondaires sont très subtils).
Ce type de problèmes peut apparaître dans de nombreux langages de programmation, pas seulement JavaScript, donc nous ne voyons pas l'un des WTF JavaScript classiques ici 1 .
Bien sûr, la question d'entrevue et les échantillons ici semblent tous très artificiels. Mais ils rappellent bien que:
1 Par exemple, vous pouvez trouver un exemple dans un langage de programmation (C #) totalement différent présentant un effet secondaire (évident) ici .
la source
Voici une autre variante, en utilisant un tableau pour masquer les valeurs que vous souhaitez.
la source
D'accord, un autre hack avec des générateurs:
la source
this
l'objet fenêtre)Utilisation de procurations :
Les proxys prétendent fondamentalement être un objet cible (le premier paramètre), mais interceptent les opérations sur l'objet cible (dans ce cas, l'opération "get property") afin qu'il y ait une possibilité de faire autre chose que le comportement par défaut de l'objet. Dans ce cas, l'action "get property" est appelée
a
lorsque==
contraint son type afin de le comparer à chaque nombre. Ça arrive:{ i: 0 }
, où lai
propriété est notre compteura
a ==
comparaison,a
le type de est contraint à une valeur primitivea[Symbol.toPrimitive]()
internea[Symbol.toPrimitive]
fonction en utilisant le "get handler"Symbol.toPrimitive
, dans ce cas , il incrémente puis retourne le compteur de l'objet cible:++target.i
. Si une propriété différente est récupérée, nous revenons simplement au retour de la valeur de propriété par défaut,target[name]
Donc:
Comme avec la plupart des autres réponses, cela ne fonctionne qu'avec une vérification d'égalité lâche (
==
), car les vérifications d'égalité strictes (===
) ne font pas de coercition de type que le proxy peut intercepter.la source
Symbol.toPrimitive
de la même manière sur un objet fonctionnerait tout aussi bien.En fait, la réponse à la première partie de la question est "Oui" dans tous les langages de programmation. Par exemple, c'est dans le cas de C / C ++:
la source
&&
le "et" logique.Identique, mais différent, mais toujours identique (peut être "testé" plusieurs fois):
Mon idée est née du fonctionnement de l'équation du type d'objet Number.
la source
Une réponse ECMAScript 6 qui utilise des symboles:
En raison de son
==
utilisation, JavaScript est censé contraindrea
quelque chose de proche du deuxième opérande (1
,2
,3
dans ce cas). Mais avant que JavaScript essaie de comprendre la contrainte par lui-même, il essaie d'appelerSymbol.toPrimitive
. Si vous fournissezSymbol.toPrimitive
JavaScript, utilisez la valeur renvoyée par votre fonction. Sinon, JavaScript appelleraitvalueOf
.la source
Je pense que c'est le code minimal pour l'implémenter:
Création d'un objet factice avec une coutume
valueOf
qui incrémente une variable globalei
à chaque appel. 23 personnages!la source
Celui-ci utilise le defineProperty avec un bel effet secondaire provoquant une variable globale!
la source
a
:get: (a => () => ++a)(0),
pas de global nécessaire.En remplaçant
valueOf
dans une déclaration de classe, cela peut être fait:Ce qui se passe, c'est que cela
valueOf
est appelé dans chaque opérateur de comparaison. Sur le premier,a
sera égal1
, sur le second,a
sera égal2
, et ainsi de suite et ainsi de suite, car à chaquevalueOf
appel, la valeur dea
est incrémentée.Par conséquent, le fichier console.log se déclenchera et sortira (dans mon terminal de toute façon)
Thing: { value: 4}
, indiquant que le conditionnel était vrai.la source