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

Note du modérateur: Veuillez résister à l’envie de modifier le code ou de supprimer cette notice. Le motif des espaces peut faire partie de la question et ne doit donc pas être altéré inutilement. Si vous êtes dans le camp des “espaces insignifiants”, vous devriez pouvoir accepter le code tel quel.

Est-il possible que (a== 1 && a ==2 && a==3) considéré comme true en JavaScript?

Ceci est une question d’interview posée par une grande entreprise de technologie. Cela s’est passé 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.

Si vous tirez parti de la façon dont == fonctionne , vous pouvez simplement créer un object avec une fonction toSsortingng (ou valueOf ) personnalisée qui modifie ce qu’elle retourne chaque fois qu’elle est utilisée, de manière à satisfaire aux trois conditions.

 const a = { i: 1, toSsortingng: function () { return a.i++; } } if(a == 1 && a == 2 && a == 3) { console.log('Hello World!'); } 

Je n’ai pas pu résister – les autres réponses sont sans aucun doute vraies, mais vous ne pouvez vraiment pas passer le code suivant:

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

C’EST POSSIBLE!

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

Exemple sans getters ou valueOf:

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

Si on lui demande si c’est possible (non obligatoire), il peut demander à “a” de renvoyer 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; } } } 

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

Cela peut être accompli en utilisant les éléments suivants dans le cadre global. Pour nodejs utilisez global au lieu de window dans 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'); } 

Cela est possible dans le cas où la variable a est accédée par, disons 2 travailleurs du 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 du réseau mettent à jour la variable juste à temps pour que les conditions a==1 , a==2 et a==3 soient satisfaites.

Cela peut être un exemple de condition de concurrence dans un environnement multithread fourni par les travailleurs Web et SharedArrayBuffer en JavaScript.

Voici l’implémentation de base 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) 

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

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

entrer la description de l'image ici

Deuxième essai:

entrer la description de l'image ici

Comme je l’ai dit, les chances seront faibles, mais avec suffisamment de temps, la situation sera au rendez-vous.

Astuce: si cela prend trop de temps sur votre système. Essayez uniquement a == 1 && a == 2 et changez Math.random()*3 en Math.random()*2 . L’ajout de plus en plus à la liste diminue les chances de bash.

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

Je ne vois pas cette réponse déjà affichée, alors je vais aussi lancer celle-ci dans le mélange. Ceci est similaire à la réponse de Jeff avec l’espace Hangul demi-largeur.

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

Vous pouvez également utiliser une classe pour cela 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!'); } 

JavaScript

a == a +1

En JavaScript, il n’y a pas d’ entiers, mais seulement des Number s, qui sont implémentés en tant que nombres à virgule flottante double précision.

Cela signifie que si un nombre a est assez 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!"); } 

Oui c’est possible! 😎

»JavaScript

 if‌=()=>!0; var a = 9; if‌(a==1 && a== 2 && a==3) { document.write("

Yes, it is possible!😎

") }

Ceci est 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 et 3 .

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

Règle numéro un des interviews; ne jamais dire impossible.

Pas besoin de ruse cachée.

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

Honnêtement, cependant, qu’il y ait un moyen de s’évaluer ou non (et comme d’autres l’ont montré, il y a plusieurs façons), la réponse que je rechercherais, en parlant en tant que quelqu’un qui a mené des centaines d’entretiens, serait: quelque chose comme:

“Eh bien, peut-être que oui dans certaines circonstances étranges qui ne sont pas immédiatement évidentes pour moi … mais si je rencontrais cela dans du code réel, j’utiliserais des techniques de débogage communes pour comprendre comment et pourquoi il faisait ce qu’il faisait et puis immédiatement refactoriser le code pour éviter cette situation … mais plus important encore: je n’écrirais absolument JAMAIS ce code car c’est la définition même du code convolué, et je m’efforce de ne jamais écrire de code compliqué “.

Je suppose que certains intervieweurs s’offusqueraient de ce que l’on appelle évidemment une question très délicate, mais cela ne me dérange pas pour les développeurs qui ont une opinion, surtout quand ils peuvent la sauvegarder avec une pensée raisonnée et intégrer ma question dans une déclaration significative sur eux-mêmes.

Here’s another variation, using an array to pop off whatever values you want.

 const a = { n: [3,2,1], toSsortingng: function () { return anpop(); } } if(a == 1 && a == 2 && a == 3) { console.log('Yes'); } 

If you ever get such an interview question (or notice some equally unexpected behavior in your code) think about what kind of things could possibly cause a behavior that looks impossible at first glance:

  1. Encoding : In this case the variable you are looking at is not the one you think it is. This can happen if you intentionally mess around with Unicode using homoglyphs or space characters to make the name of a variable look like another one, but encoding issues can also be introduced accidentally, eg when copying & pasting code from the Web that contains unexpected Unicode code points (eg because a content management system did some “auto-formatting” such as replacing fl with Unicode ‘LATIN SMALL LIGATURE FL’ (U+FB02)).

  2. Race conditions : A race-condition might occur, ie a situation where code is not executing in the sequence expected by the developer. Race conditions often happen in multi-threaded code, but multiple threads are not a requirement for race conditions to be possible – asynchronicity is sufficient (and don’t get confused, async does not mean multiple threads are used under the hood ).

    Note that therefore JavaScript is also not free from race conditions just because it is single-threaded. See here for a simple single-threaded – but async – example. In the context of an single statement the race condition however would be rather hard to hit in JavaScript.

    JavaScript with web workers is a bit different, as you can have multiple threads. @mehulmpt has shown us a great proof-of-concept using web workers .

  3. Side-effects : A side-effect of the equality comparison operation (which doesn’t have to be as obvious as in the examples here, often side-effects are very subtle).

These kind of issues can appear in many programming languages, not only JavaScript, so we aren’t seeing one of the classical JavaScript WTFs here 1 .

Of course, the interview question and the samples here all look very consortingved. But they are a good reminder that:

  • Side-effects can get really nasty and that a well-designed program should be free from unwanted side-effects.
  • Multi-threading and mutable state can be problematic.
  • Not doing character encoding and ssortingng processing right can lead to nasty bugs.

1 For example, you can find an example in a totally different programming language (C#) exhibiting a side-effect (an obvious one) here .

Okay, another hack with generators:

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

Actually the answer to the first part of the question is “Yes” in every programming language. For example, this is in the case of 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; } 

Same, but different, but still same (can be “tested” multiple times):

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

Using Proxies :

 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 basically pretend to be a target object (the first parameter), but intercept operations on the target object (in this case the “get property” operation) so that there is an opportunity to do something other than the default object behavior. In this case the “get property” action is called on a when == coerces its type in order to compare it to each number. This happens:

  1. We create a target object, { i: 0 } , where the i property is our counter
  2. We create a Proxy for the target object and assign it to a
  3. For each a == comparison, a ‘s type is coerced to a primitive value
  4. This type coercion results in calling a[Symbol.toPrimitive]() internally
  5. The Proxy intercepts getting the a[Symbol.toPrimitive] function using the “get handler”
  6. The Proxy’s “get handler” checks that the property being gotten is Symbol.toPrimitive , in which case it increments and then returns the counter from the target object: ++target.i . If a different property is being resortingeved, we just fall back to returning the default property value, target[name]

Alors:

 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 

As with most of the other answers, this only works with a loose equality check ( == ), because ssortingct equality checks ( === ) do not do type coercion that the Proxy can intercept.

I think this is the minimal code to implement it:

 i=0,a={valueOf:()=>++i} if (a == 1 && a == 2 && a == 3) { console.log('Mind === Blown'); } 

An ECMAScript 6 answer that makes use of Symbols:

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

Due to == usage, JavaScript is supposed to coerce a into something close to the second operand ( 1 , 2 , 3 in this case). But before JavaScript sortinges to figure coercing on its own, it sortinges to call Symbol.toPrimitive . If you provide Symbol.toPrimitive JavaScript would use the value your function returns. If not, JavaScript would call valueOf .

This one uses the defineProperty with a nice side-effect causing global variable!

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