Est-ce que (a == 1 && a == 2 && a == 3) peut être évalué comme vrai?


2484

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é trueen 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.


9
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
décomposer

109
Aux personnes qui ont apparemment voté pour considérer cela comme trop large : est-ce une fouille sur Javascript, en disant qu'il y a trop de réponses valides?
tomsmeding

24
Certaines personnes s'asseyent autour de philosopher sur ce qui est possible. D'autres concentrent leurs efforts sur la création ou non de produits viables et adaptés à leurs clients. OMI, cette question n'a aucune utilité pratique au-delà du fait que vous ne devriez jamais poser ce genre de questions dans une interview ou écrire ce genre de code. C'est pourquoi il devrait être fermé. Je veux dire vraiment, l'entreprise se rend-elle compte qu'elle a payé quelqu'un de l'argent réel pour s'asseoir et parler de ce genre de choses?
P.Brian.Mackey

15
Après avoir lu les réponses, les mœurs de l'histoire sont: ne pas utiliser ==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.
Jesse C. Slicer du

87
Note du modérateur: Stack Overflow a eu une histoire de gens qui ont donné des réponses dans différentes langues à celle en question. Ce sont des tentatives pour répondre à la question parce qu'elles sont des solutions au problème général, bien que dans une langue différente. Veuillez ne pas les signaler comme "pas une réponse". Cela dit, veuillez également ne pas publier plus de réponses dans différentes langues - il y a une raison pour laquelle cette question est spécifique à JavaScript, comme le soulignent les commentaires sous certaines de ces autres réponses, et il y a une raison pour laquelle nous aimons nos questions spécifiques à la langue le rester.
BoltClock

Réponses:


3323

Si vous profitez de la façon dont ==fonctionne , vous pouvez simplement créer un objet avec une fonction personnalisée toString(ou valueOf) qui change ce qu'il retourne chaque fois qu'il est utilisé de telle sorte qu'il remplit les trois conditions.

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

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


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 valueOfs'il est appelable, et à défaut, il appellera toString. J'ai utilisé toStringdans ce cas simplement parce que c'est ce qui m'est venu à l'esprit, valueOfaurait plus de sens. Si j'avais plutôt renvoyé une chaîne toString, 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.


70
Pourriez-vous y parvenir en modifiant l' valueOf()opération implicite ?
Sterling Archer

43
Oui, valueOf fonctionne à la place de toString pour la même raison
Kevin B

4
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
décomposer

13
En fonction de cela, une conversion de nombre sera tentée en premier, donc valueOfc'est légèrement mieux.
Salman A

6
@Pureferret le côté gauche de la comparaison d'égalité est un objet, pas un nombre. Le fait que cet objet ait une propriété numérique ine dérange pas le moteur. ;)
tomsmeding

2057

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:

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

Notez l'espacement étrange dans la ifdé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:

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

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:

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
À en juger par l'espacement étrange de la question d'origine, je pense que c'est EXACTEMENT la réponse que la question de l'entretien cherchait - exploiter des personnages non spatiaux qui ressemblent à des espaces. Bon endroit!
Baracus

18
@Baracus C'est RonJohn qui a remarqué l'espacement étrange dans son commentaire sur la réponse de Kevin qui m'a rappelé cette (horrible) technique, donc je ne peux pas m'attribuer le mérite de l'avoir repérée. J'ai été un peu surpris que personne n'ait déjà répondu à cela, car cela a fait le tour de mon travail il y a quelques années à cause d'un article de blog quelque part - je supposais en quelque sorte que c'était assez connu à ce jour.
Jeff

102
Bien sûr, cela est interdit comme échappatoire standard , ce qui s'applique également aux entretiens. [citation nécessaire]
Sanchises

13
Compte tenu de l'espacement d'origine, il pourrait être encore pire, c'est-à-dire qu'une variable var ᅠ2 = 3a été utilisée; donc il y a les trois variables aᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3, pour que (a␣==1 && a==␣2 && a==3))…
Holger

2
@ AL-zami, il y a un caractère supplémentaire dans deux des variables, qui apparaît sur votre écran comme un espace, mais est interprété comme faisant partie de l'identifiant, ce qui signifie qu'il y a trois variables distinctes - a, a et a - le caractère supplémentaire est l'espace demi-largeur Hangul.
Jeff

620

C'EST POSSIBLE!

var i = 0;

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

Cela utilise un getter à l'intérieur d'une withinstruction 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 ===.

  var i = 0;

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


65
Oui, j'essayais la même chose :) Donc, la bonne réponse dans l'interview serait: "Cela ne peut pas arriver dans mon code car je ne l'utilise jamais with."
Pointy

7
@Pointy - Et, je programme en mode strict où ce withn'est pas autorisé.
jfriend00

6
@Pointy dans la réponse acceptée, ils font quelque chose de similaire sans withque cela puisse arriver
Jungkook

2
@jorrit que personne n'utiliserait ==. Et ===empêche la réponse acceptée
Jonas Wilms

4
@JonasW. Beaucoup de gens utilisent encore ==mais je n'ai pas vu withdepuis ... 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.
wortwart

516

Exemple sans getters ou valueOf:

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

Cela fonctionne car ==invoque toStringqui appelle .joindes tableaux.

Une autre solution, utilisant Symbol.toPrimitivequi est un équivalent ES6 de toString/valueOf:

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

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


9
without valueOf, eh bien ... c'est plus indirect mais essentiellement la même chose.
Jonas Wilms

11
J'aime vraiment cette solution parce que vous ne remplacez rien d'autre que la fonction de jointure des objets, et c'est juste un hack très propre et facile à lire qui rend la logique évaluée comme vraie.
Alex Pedersen

28
Honnêtement, je pense que c'est la meilleure réponse. Il n'implique rien d'extraordinaire, il suffit de définir quelques valeurs. Très facile à comprendre même avec des connaissances de base de JS. Bien joué.
Zac Delventhal

14
Cela a tellement de sens que cela semble presque utile.
Andrew

7
Je savais que la plupart des réponses concerneraient l'abus toStringou, valueOfmais celle-ci m'a complètement pris au dépourvu. Très intelligent et je ne savais pas qu'il appelait en .joininterne, mais c'est tout à fait logique.
GBarroso

268

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.

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
Je donnerais délibérément cette réponse même si je connaissais les autres solutions, car elle répond à la question mais n'est évidemment pas ce qu'elles recherchaient. Jouez à des jeux stupides, gagnez des prix stupides.
ESR

2
Mais que faire si cela prend plus de 1000 essais?
Piyin

9
@Piyin S'il faut plus de 1000 essais, vous gagnez un prix!
Skeets

5
J'aime cette réponse parce que la pousser à l'extrême suggère que cela est possible dans n'importe quelle langue si les registres / cache du processeur sont frappés avec suffisamment de rayons cosmiques pendant que le programme est en cours d'exécution, ou si l'on effectue délibérément un problème de puissance tel que la branche de défaillance de le conditionnel ne saute pas réellement.
Ponkadoodle

Le plus bas: 1, le plus haut: 412.
KyleFairns

210

Lorsque vous ne pouvez rien faire sans expressions régulières:

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

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

Il fonctionne en raison de la valueOfméthode personnalisée qui est appelée lorsque Object est comparé à une primitive (telle que Number). L'astuce principale est de a.valueOfrenvoyer une nouvelle valeur à chaque fois car elle appelle execune expression régulière avec gindicateur, ce qui provoque la mise à jour lastIndexde cette expression régulière à chaque fois qu'une correspondance est trouvée. Donc , première fois this.r.lastIndex == 0, il correspond 1et mises à jour lastIndex: this.r.lastIndex == 1, donc la prochaine fois regex correspondra 2et ainsi de suite.


22
@Abdillah un objet regex se souviendra du dernier index auquel il correspond, appelez à execnouveau commencera la recherche à partir de cet index. MDN n'est pas très clair.
Simon Chan

Je vois, donc l' this.robjet regex se souvient de l'état / index. Merci!
Abdillah

Je recommanderais cependant de passer une chaîne exec, pas un entier à stringifier.
Bergi

utilisez l'expression régulière et vous avez maintenant deux problèmes
Aleksey Solovey

191

Cela peut être accompli en utilisant ce qui suit dans la portée globale. À nodejsutiliser globalau lieu de windowdans le code ci-dessous.

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

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.


Cela suppose que ac'est une propriété thisdont il ne semble pas être. S'il as'agissait d'une variable locale (à laquelle elle ressemble), cela ne fonctionnerait pas.
jfriend00

1
@ jfriend00 tu veux dire si tu as placé var a; quelque part?
jontro

Ouais. Le référencement a == 1implique qu'une avariable est quelque part, et non une propriété de this. Bien qu'il existe un endroit étrange comme les globaux où les deux pourraient être vrais, généralement, déclarer une variable avec var aou let asignifie qu'il n'y a pas de thisqui vous permet d'accéder en atant 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.
jfriend00

@ jfriend00 bien sûr. Pas sûr que cela ajouterait beaucoup plus de valeur en combinaison avec les autres réponses déjà.
Mettra à

14
La question était de savoir si cela pouvait "jamais" être vrai. Et la réponse est oui, et c'est l'un des scénarios où cela pourrait être vrai: an'est pas une variable locale et est défini sur la portée globale avec un getter incrémentiel.
Zac Delventhal

190

Ceci est possible en cas d' aaccè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 variable ajuste à temps pour que les conditions a==1, a==2eta==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

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

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

Sur mon MacBook Air, cela se produit après environ 10 milliards d'itérations lors de la première tentative:

entrez la description de l'image ici

Deuxième essai:

entrez la description de l'image ici

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 == 2et passez Math.random()*3à Math.random()*2. Ajouter de plus en plus à la liste diminue les chances de frapper.


50
Honnêtement, c'est la meilleure réponse. Toutes les autres réponses nécessitent une tentative délibérée de faire quelque chose de profondément peu intuitif. Cette réponse reflète en fait quelque chose qui pourrait arriver dans le monde réel - une condition de race.
Tom Swirly

34
Non seulement cela - j'ai vu cela se produire dans le monde réel. Pas avec la condition exacte dans la question, mais certainement avec la vérification (a == 1) au début d'une fonction et (a == 2) plus tard dans la fonction, et le fait que le code rencontre les deux conditions. Pour info, la première fois que j'ai vu cela se produire était dans un contrôleur de moteur de voiture, et nous avons mis en place des normes de codage. La deuxième fois, c'était dans un système de distribution de balles et de torches pour les avions militaires, et lors de mon premier jour dans l'entreprise, j'ai trouvé cela et l'ai corrigé, tandis que le reste de l'équipe discutait toujours du problème. (Niveau de félicitations: élevé! :)
Graham

38
Vous avez donc travaillé sur les "contrôleurs de moteur de voiture" et les "systèmes de distribution de paillettes et de torches" qui sont programmés en javascript avec les travailleurs du web? Je ne pense pas que je retournerai dehors.
psaxton

12
@psaxton :) Bien sûr que non - mais nous avons un logiciel multi-thread avec des données partagées. Il s'agit d'un anti-modèle pour tous les logiciels multithreads, non spécifique à Javascript ou aux travailleurs du Web. Peu importe que vous programmiez en langage assembleur, Brainf * ck, Visual BASIC, C ou Javascript - si vous le faites avec des données partagées dans une application multi-thread, cela échouera toujours .
Graham

4
Je pense que c'est maintenant un wrapper élaboré autour de la réponse de @ jontro.
qntm

148

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

(() => {
    "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
Notez que l'approche d'utiliser un getter fonctionne également avec ===, pas seulement ==.
Makyen

Cette solution repose sur le fait d' thisêtre l'objet global à l'intérieur du corps de la fonction flèche.
Roy Tinker du

@Midnightas Je ne catégoriserais aucune autre réponse comme "code pyramidal" .
Patrick Roberts

Notez que cela fonctionne également avec un ordre arbitraire, n'est-ce pas? Comme (a == 3 && a == 2 && a == 1),?
Johannes

131

Alternativement, vous pouvez utiliser une classe pour elle et une instance pour la vérification.

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

var a = new A;

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

ÉDITER

En utilisant les classes ES6, cela ressemblerait à ceci

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
juste function A() {value = 0;au début?
Dave C

valueOfest remplacé, this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codedonc quand on compare la valeur, il incrémente en fait un ..
Danyal Sandeelo

130

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.

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

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 A
- Minuscules latines pleine largeur A
а - Minuscules cyrilliques A

Le 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) vs wikipedia.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.


19
"Légère divergence" n'est pas ainsi que j'appellerais cela.

4
@hvd dépend entièrement du rendu de votre police. Voilà ce que je vois .
Draco18 ne font plus confiance au SE le

1
@Jake Ouais, le minuscule latin pleine largeur A n'est pas le plus grand homoglyphe (mais les variantes en majuscules sont incroyables). Généralement, il n'en faut que deux pour obtenir l'effet souhaité.
Draco18 ne font plus confiance au SE le

@ Draco18s D'accord: seulement 2 sont généralement nécessaires. Bon travail sur l'info supplémentaire aussi!
JakeSteam

10
Vous pouvez également utiliser le sélecteur de variante unicode (U + FE00..U + FE0F). Aucun d' entre eux sont a: a︀ a︁ a︂. Ne vous inquiétez plus des écarts.
Salman A

108

Oui c'est possible! 😎

»JavaScript

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

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

Le code ci-dessus est une version courte (merci à @Forivin pour sa note dans les commentaires) et le code suivant est 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;}

Si vous voyez juste le côté supérieur de mon code et l'exécutez, vous dites WOW, comment?

Donc je pense qu'il suffit de dire oui, c'est possible à quelqu'un qui vous a dit: rien n'est impossible

Astuce: j'ai utilisé un caractère caché après ifpour créer une fonction à laquelle son nom ressemble if. En JavaScript, nous ne pouvons pas remplacer les mots clés, j'ai donc forcé à utiliser de cette façon. C'est un faux if, mais ça marche pour vous dans ce cas!


» C #

J'ai également écrit une version C # ( avec une technique d'augmentation de la valeur des propriétés ):

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

Démo en direct


56
La version javascript est un véritable crime contre l'humanité et la possibilité de le faire devrait être illégale par les conventions de l'ONU. Je pense qu'il est temps de purger le monde de toute connaissance de javacript.
Plus clair

2
La déclaration de fonction pourrait être encore plus courte. if‌=()=>!0
Forivin

4
Pourquoi diable avez-vous utilisé document.write? C'est un moyen infaillible de ne pas être embauché, peu importe le reste de la réponse.
Cerbrus

3
@Cerbrus, Merci pour votre note. J'ai d'abord écrit ma réponse avec console.logmais je l'ai changé en document.write. Je l'utilise vraiment toujours console.logdans 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é par console.log. Cliquez sur le Run Code Snippetbouton 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.
RAM

1
@Clearer, Si les conventions des Nations Unies pouvaient changer le monde efficacement, alors nous devrions avoir un monde meilleur que celui-ci. Nous avons besoin de quelque chose de plus qu'une déclaration à l'ONU et jusqu'à ce jour, je pense que nous pouvons utiliser cette astuce Javascript;)
RAM

97

Javascript

a == a +1

En JavaScript, il n'y a pas d' entiers mais seulement des Numbers, qui sont implémentés comme des nombres à virgule flottante double précision.

Cela signifie que si un nombre aest suffisamment grand, il peut être considéré comme égal à trois entiers consécutifs:

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

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==3solutions en Ruby et Python. Avec une légère modification, c'est également possible en Java.

Rubis

Avec une coutume ==:

class A
  def ==(o)
    true
  end
end

a = A.new

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

Ou une augmentation 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

Il est possible de modifier le 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 :) Il y a déjà suffisamment de bonnes réponses JS. Je pensais juste qu'il serait intéressant de montrer comment cela peut être fait dans d'autres langues, et éventuellement de donner des idées aux développeurs JS.
Eric Duminil

2
@ cᴏʟᴅsᴘᴇᴇᴅ: mis à jour avec un exemple JS.
Eric Duminil

1
Pourquoi la version Java ne fonctionne-t-elle pas Integer a = 42(ou fonctionne-t-elle)? Si je comprends bien la Integer a = 42; a == 1 && a == 2 && a == 3boîte automatique, devrait encadrer toutes les entrées. Ou cela déballe-t-il un pour les comparaisons?
CAD97

@ CAD97: Integer == intsemble entraîner le déballage. Mais en utilisant les Integer#equals(int)forces de l'autoboxing, cela fonctionne. Merci pour le commentaire!
Eric Duminil

@StephanBijzitter: Veuillez expliquer. Pour autant que je sache, il n'y en a que Numbersdans JS, qui sont essentiellement comme l' doubleart. 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 cela n == n + 1puisse jamais être vrai pour les entiers en Java / Python / C / Ruby / ...
Eric Duminil

80

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, 2et 3.

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

* 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:

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

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


75

Règle numéro un des entretiens; ne dites jamais impossible.

Pas besoin de tromperie de personnage caché.

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
Aie. __defineGetter__ne fait en fait pas partie du langage js, juste une version laide de defineProperty. typeofn'est pas une fonction et ce non déclaré iest tout simplement horrible. Semble toujours valoir 40 votes positifs: /
Jonas Wilms

6
@JonasW. 41 votes positifs :-) Je suis conscient que __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 de defineProperty()car le code hérité est réel et ne peut être ignoré. Indépendamment de la laideur, déclarer icomme je l'ai fait est un comportement bien connu / documenté. Peut-être que j'étais juste d'humeur PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus

68

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.


13
La question (ou toutes les questions d'entrevue) est probablement de tester la volonté des candidats à réfléchir à un problème, en particulier ceux qui sont "apparemment évidents", comme celui-ci. Quelqu'un qui refuse de penser parce qu'il pense "connaître" la réponse n'est pas une bonne personne.
Shammoo

5
@Don Hatch Non, je ne les pénaliserais pas s'ils répondaient de bonne foi et surtout s'ils donnaient une réponse correcte comme les autres l'ont montré ... mais je demanderais ensuite un suivi pour essayer de sonder s'ils pensent que c'est un bon moyen d'écrire du code ou non. Être bien informé et être capable de trouver une réponse «correcte» n'est qu'une partie du bon développeur. Beaucoup plus important pour un développeur "professionnel" est d'écrire du code compréhensible et maintenable sur la route, souvent par des développeurs moins compétents. Les développeurs trop intelligents sont à peu près aussi mauvais que les développeurs incapables IME.
Frank W. Zammetti

16
Cela ne répond pas à la question.
TylerH

6
La chose triste à propos de cette réponse est qu'un utilisateur 1rep a répondu hier et a obtenu 2 downvotes, ce qui l'a obligé à supprimer cette question.
Jonas Wilms

8
@JohnColeman, la question demande comment le code pourrait être évalué comme vrai. Il ne demande pas les raisons pour lesquelles l'intervieweur a proposé la question en premier lieu. Cette réponse ne tente même pas de répondre à la question posée, et se concentre plutôt entièrement sur une version «ce que je ferais» d'une tentative de deviner quel était le but de l'intervieweur. Si telle était la question posée, elle serait beaucoup trop large. Par conséquent, cette réponse n'appartient pas ici ou n'importe où sur le site.
TylerH

43

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:

  1. 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 flpar Unicode 'LATIN SMALL LIGATURE FL' (U + FB02)).

  2. 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 .

  3. 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:

  • Les effets secondaires peuvent devenir vraiment désagréables et qu'un programme bien conçu devrait être exempt d'effets secondaires indésirables.
  • L'état multithread et mutable peut être problématique.
  • Ne pas faire correctement l'encodage des caractères et le traitement des chaînes peut conduire à des bugs désagréables.

1 Par exemple, vous pouvez trouver un exemple dans un langage de programmation (C #) totalement différent présentant un effet secondaire (évident) ici .


1
Ensuite, la question devient beaucoup trop large. Différentes langues peuvent implémenter cela avec différents degrés de facilité. La question a gagné en popularité car il s'agit d'un QS spécifique à JS, mais ce n'est que mon 2c.
cs95

1
les causes sont différentes C # et javascript donc cette réponse n'est pas légitime.
Edwin

3
@Edwin: Les causes sont exactement les mêmes: Unicode jouant avec des glyphes ou des caractères spatiaux d'aspect similaire, des conditions de concurrence ou des effets secondaires de l'opération de comparaison (ces derniers étant illustrés dans mon exemple).
Dirk Vollmar

2
@ cᴏʟᴅsᴘᴇᴇᴅ: Parfois, regarder les choses sous un angle plus large permet de voir le problème réel.
Dirk Vollmar

3
Je souhaite que cette réponse puisse être associée à cette question d'une manière "méta". Après avoir lu toutes les réponses ci-dessus, je me sentais comme JS a tellement de trous, mais vous venez de résumer toutes les réponses en une seule fois. Et vous l'avez fait d'une manière qui en fait une question d'entrevue stellaire (si la balise spécifique à la langue est supprimée) à mon avis. Bravo!
KCE

41

Voici une autre variante, en utilisant un tableau pour masquer les valeurs que vous souhaitez.

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

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


31

D'accord, un autre hack avec des générateurs:

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


Vous dites pirater, mais je suis presque sûr que c'est le cas d'utilisation des générateurs ... :) (enfin, sauf que cela dépend de thisl'objet fenêtre)
Cody

29

Utilisation de procurations :

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

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 alorsque ==contraint son type afin de le comparer à chaque nombre. Ça arrive:

  1. Nous créons un objet cible { i: 0 }, où la ipropriété est notre compteur
  2. Nous créons un proxy pour l'objet cible et l'affectons à a
  3. Pour chaque a ==comparaison, ale type de est contraint à une valeur primitive
  4. Ce type de coercition conduit à appeler en a[Symbol.toPrimitive]()interne
  5. Le proxy intercepte l'obtention de la a[Symbol.toPrimitive]fonction en utilisant le "get handler"
  6. Les chèques « gestionnaire » de proxy obtenir que la propriété se récupérer est 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:

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

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.


2
Il n'y a aucun intérêt à utiliser un proxy pour cela, cependant - définir Symbol.toPrimitivede la même manière sur un objet fonctionnerait tout aussi bien.
Ry-

27

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 ++:

#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
Je ne pense pas que ce soit possible dans tous les langages de programmation. Par exemple, toutes les langues n'ont pas de préprocesseurs. D'ailleurs, toutes les langues n'utilisent pas &&le "et" logique.
Keith Thompson

3
J'ai trouvé un moyen qui fonctionne à la fois en Python et C ++ qui utilise la surcharge d'opérateur.
Donald Duck

7
Et vous pouvez le faire en Java en utilisant la réflexion et en gâchant le cache d'entiers.
CAD97

7
Impossible de le faire dans des langues qui ne prendraient pas en charge la mutation à cet endroit, par exemple, rien de comparable n'est disponible dans haskell
Jason Carr

4
La question concerne JavaScript, pas C ++.
Tous les travailleurs sont essentiels

26

Identique, mais différent, mais toujours identique (peut être "testé" plusieurs fois):

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

Mon idée est née du fonctionnement de l'équation du type d'objet Number.


4
Fonctionne également une deuxième fois!
Salman A

25

Une réponse ECMAScript 6 qui utilise des symboles:

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

En raison de son ==utilisation, JavaScript est censé contraindre aquelque chose de proche du deuxième opérande ( 1,2 , 3dans ce cas). Mais avant que JavaScript essaie de comprendre la contrainte par lui-même, il essaie d'appeler Symbol.toPrimitive. Si vous fournissez Symbol.toPrimitiveJavaScript, utilisez la valeur renvoyée par votre fonction. Sinon, JavaScript appellerait valueOf.


24

Je pense que c'est le code minimal pour l'implémenter:

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

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

Création d'un objet factice avec une coutume valueOfqui incrémente une variable globale ià chaque appel. 23 personnages!


14

Celui-ci utilise le defineProperty avec un bel effet secondaire provoquant une variable globale!

var _a = 1

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

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


8
vous pouvez utiliser une fermeture sur a: get: (a => () => ++a)(0),pas de global nécessaire.
Nina Scholz

13
@NinaScholz bien sûr, mais nous parlons de mauvaises pratiques ici - laissez-moi juste ceci: D
Ben Aubin

1

En remplaçant valueOfdans une déclaration de classe, cela peut être fait:

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

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

const a = new Thing();

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

Ce qui se passe, c'est que cela valueOfest appelé dans chaque opérateur de comparaison. Sur le premier, asera égal 1, sur le second, asera égal 2, et ainsi de suite et ainsi de suite, car à chaque valueOfappel, la valeur de aest 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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.