¿Puede (a == 1 && a == 2 && a == 3) alguna vez evaluar como verdadero?

2484

Nota para el moderador: resista la necesidad de editar el código o eliminar este aviso. El patrón de espacios en blanco puede ser parte de la pregunta y, por lo tanto, no debe ser manipulado innecesariamente. Si está en el campo "el espacio en blanco es insignificante", debería poder aceptar el código tal como está.

¿Es posible que se (a== 1 && a ==2 && a==3)pueda evaluar trueen JavaScript?

Esta es una pregunta de entrevista realizada por una importante empresa de tecnología. Sucedió hace dos semanas, pero todavía estoy tratando de encontrar la respuesta. Sé que nunca escribimos ese código en nuestro trabajo diario, pero tengo curiosidad.

Dimpu Aravind Buddha
fuente
99
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
deceze
109
Para las personas que aparentemente votaron a cloae esto como demasiado amplio : ¿eso es una excavación en Javascript, diciendo que hay demasiadas respuestas válidas?
tomsmeding
24
Algunas personas se sientan a filosofar sobre lo que es posible. Otros centran sus esfuerzos en si están construyendo o no productos viables y comerciales para sus clientes. En mi opinión, esta pregunta no tiene ninguna utilidad práctica más allá del hecho de que nunca debe hacer este tipo de preguntas en una entrevista o escribir este tipo de código. Por eso debería estar cerrado. Quiero decir realmente, ¿se da cuenta la empresa que le pagó a alguien dinero real para sentarse y hablar sobre estas cosas?
P.Brian.Mackey
15
Después de leer las respuestas, la moraleja de la historia es: no la use ==cuando quiera decir ===, tenga un estándar de codificación que prohíba nombres de variables que no sean ASCII y tenga un proceso de unión que refuerce las dos morales anteriores.
Jesse C. Slicer
87
Nota para el moderador: Stack Overflow ha tenido una historia de personas interviniendo con respuestas en diferentes idiomas al en cuestión. Estos son intentos de responder a la pregunta porque son soluciones al problema general, aunque en un idioma diferente. Abstenerse de marcarlos como "no es una respuesta". Dicho esto, también abstenerse de publicar más respuestas en diferentes idiomas: hay una razón por la que esta pregunta es específica de JavaScript, como lo señalan los comentarios en algunas de estas otras respuestas, y hay una razón por la que nos gustan nuestras preguntas específicas de idioma permanecer así.
BoltClock

Respuestas:

3323

Si aprovecha cómo ==funciona , podría simplemente crear un objeto con una función personalizada toString(o valueOf) que cambie lo que devuelve cada vez que se usa de modo que satisfaga las tres condiciones.

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

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


La razón por la que esto funciona se debe al uso del operador de igualdad suelta. Cuando se utiliza la igualdad suelta, si uno de los operandos es de un tipo diferente al otro, el motor intentará convertir uno a otro. En el caso de un objeto a la izquierda y un número a la derecha, intentará convertir el objeto en un número llamando primero valueOfsi es invocable y, en su defecto, llamará toString. Lo usé toStringen este caso simplemente porque es lo que se me ocurrió, valueOftendría más sentido. Si en cambio devolviera una cadena toString, el motor habría intentado convertir la cadena en un número que nos diera el mismo resultado final, aunque con una ruta un poco más larga.

Kevin B
fuente
70
¿Podría lograr esto alterando la valueOf()operación implícita ?
Sterling Archer
43
Sí, valueOf funciona en lugar de toString por la misma razón
Kevin B
44
Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
deceze
13
De acuerdo con esto, primero se intentará una conversión de número, por lo que valueOfes un poco mejor.
Salman A
66
@Pureferret, el lado izquierdo de la comparación de igualdad es un objeto, no un número. Que ese objeto tenga una propiedad numérica ino molesta al motor. ;)
tomsmeding
2057

No pude resistirme; las otras respuestas son indudablemente ciertas, pero realmente no puedes pasar el siguiente código:

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

Tenga en cuenta el espacio extraño en la ifdeclaración (que copié de su pregunta). Es el Hangul de ancho medio (que es coreano para aquellos que no están familiarizados) que es un carácter de espacio Unicode que el script ECMA no interpreta como un carácter de espacio; esto significa que es un carácter válido para un identificador. Por lo tanto, hay tres variables completamente diferentes, una con el Hangul después de la a, otra con ella antes y la última con solo a. Reemplazando el espacio _por legibilidad, el mismo código se vería así:

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

Echa un vistazo a la validación en el validador de nombres de variables de Mathias . Si ese espacio extraño realmente se incluyó en su pregunta, estoy seguro de que es una pista para este tipo de respuesta.

No hagas esto. Seriamente.

Editar: Ha llegado a mi conocimiento que (aunque no se les permite iniciar una variable), el carpintero de ancho cero y cero-anchura no carpintería también están autorizados los caracteres en los nombres de variables - ver la ofuscación de JavaScript con ancho cero caracteres - pros y contras ? .

Esto se vería así:

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

Jeff
fuente
368
A juzgar por el extraño espacio en la pregunta original, creo que esta es EXACTAMENTE la respuesta que buscaba la pregunta de la entrevista: explotar personajes no espaciales que parecen espacios. ¡Buen lugar!
Baracus
18
@Baracus Fue RonJohn quien notó el extraño espacio en su comentario sobre la respuesta de Kevin que me recordó esta (horrible) técnica, por lo que no puedo tomar el crédito por haberlo visto. Sin embargo, me sorprendió un poco que nadie ya hubiera respondido con esto, ya que se hizo alrededor de mi trabajo hace unos años debido a una publicación en un blog en algún lugar; asumí que era bastante conocido por ahora.
Jeff
102
Por supuesto, esto está prohibido como un vacío legal estándar , que también se aplica a las entrevistas. [cita requerida]
Sanchises
13
Considerando el espacio original, podría ser aún peor, es decir, var ᅠ2 = 3se ha utilizado una variable ; así que están las tres variables aᅠᅠ= 1, ᅠ2 = 3, a = 3( a␣ = 1, ␣2 = 3, a = 3, de modo que (a␣==1 && a==␣2 && a==3)) ...
Holger
2
@ AL-zami hay un carácter adicional en dos de las variables, que se muestra en la pantalla como un espacio, pero se interpreta como parte del identificador, lo que significa que hay tres variables separadas: a, ay a , el carácter adicional es el espacio de ancho medio Hangul.
Jeff
620

¡ES POSIBLE!

var i = 0;

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

Esto utiliza un captador dentro de una withdeclaración para permitir aevaluar tres valores diferentes.

... esto todavía no significa que deba usarse en código real ...

Peor aún, este truco también funcionará con el uso de ===.

  var i = 0;

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

Jonas Wilms
fuente
65
Sí, estaba intentando lo mismo :) Entonces, la respuesta correcta en la entrevista sería: "No puede suceder en mi código porque nunca uso with".
Puntiagudo
77
@Pointy: y programo en modo estricto donde withno está permitido.
jfriend00
66
@Pointy en la respuesta aceptada hacen algo similar sin withlo que puede suceder
Jungkook
2
@jorrit que nadie usaría ==. Y ===evita que la respuesta aceptada
Jonas Wilms
44
@JonasW. Mucha gente todavía usa, ==pero no he visto withdesde ... bueno, en realidad nunca fuera de la documentación de JS donde dice "por favor no use eso". De todos modos, una buena solución.
wortwart
516

Ejemplo sin captadores o valueOf:

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

Esto funciona porque ==invoca lo toStringque requiere .joinmatrices.

Otra solución, utilizando Symbol.toPrimitivecuál es un equivalente ES6 de toString/valueOf:

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

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

georg
fuente
99
without valueOf, bueno ... es más indirecto pero básicamente lo mismo.
Jonas Wilms
11
Realmente me gusta esta solución porque no anula nada más que la función de unión propia de los objetos, y es solo un truco muy limpio y fácil de leer que hace que la lógica se evalúe como verdadera.
Alex Pedersen
28
Sinceramente, creo que esta es la mejor respuesta. No implica nada fuera de lo común, solo establece algunos valores. Muy fácil de entender incluso con conocimientos básicos de JS. Bien hecho.
Zac Delventhal
14
Esto tiene tanto sentido que casi se siente útil.
Andrew
77
Sabía que la mayoría de las respuestas serían sobre abuso toStringo abuso, valueOfpero esta me sorprendió por completo. Muy inteligente y no sabía que llamaba .joininternamente, pero tiene mucho sentido.
GBarroso
268

Si se le pregunta si es posible (no DEBE), puede pedirle a "a" que devuelva un número aleatorio. Sería cierto si genera 1, 2 y 3 secuencialmente.

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

ocomfd
fuente
102
Daría esta respuesta deliberadamente incluso si supiera las otras soluciones, porque responde la pregunta pero obviamente no es lo que buscaban. Juega juegos estúpidos, gana premios estúpidos.
ESR
2
Pero, ¿qué pasa si se necesitan más de 1000 pruebas?
Piyin
99
@Piyin ¡Si se necesitan más de 1000 pruebas, ganas un premio!
Skeets
55
Me gusta esta respuesta porque llevarla al extremo sugiere que esto es posible en cualquier idioma si los registros / caché de la CPU son golpeados con suficientes rayos cósmicos mientras el programa se está ejecutando, o si uno deliberadamente realiza una falla de energía tal que la rama de falla de el if conditional en realidad no salta.
Ponkadoodle el
Bajo: 1, más alto: 412.
KyleFairns
210

Cuando no puedes hacer nada sin expresiones regulares:

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

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

Funciona debido al valueOfmétodo personalizado que se llama cuando Object se compara con primitivo (como Number). El truco principal es que a.valueOfdevuelve un nuevo valor cada vez porque llama execa una expresión regular con un gindicador, lo que provoca la actualización lastIndexde esa expresión regular cada vez que se encuentra una coincidencia. Entonces, la primera vez this.r.lastIndex == 0, coincide 1y se actualiza lastIndex: this.r.lastIndex == 1así que la próxima vez la expresión regular coincidirá 2y así sucesivamente.

Kos
fuente
22
@Abdillah, un objeto regex recordará el último índice que coincida, la llamada execnuevamente comenzará a buscar desde ese índice. MDN no es muy claro.
Simon Chan
Ya veo, así que el this.robjeto regex recuerda el estado / índice. ¡Gracias!
Abdillah
Sin embargo, recomendaría pasar una cadena a exec, no un entero para ser stringificado.
Bergi
usa regex y ahora tienes dos problemas
Aleksey Solovey
191

Se puede lograr utilizando lo siguiente en el ámbito global. Para nodejsusar en globallugar de windowen el código a continuación.

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

Esta respuesta abusa de las variables implícitas proporcionadas por el alcance global en el contexto de ejecución definiendo un captador para recuperar la variable.

jontro
fuente
Esto supone que aes una propiedad de la thisque no parece ser. Si afuera una variable local (como se ve), entonces esto no funcionaría.
jfriend00
1
@ jfriend00 quieres decir si colocaste var a; ¿algun lado?
jontro
Si. La referencia a == 1implica que aes una variable en algún lugar, no una propiedad de this. Si bien hay un lugar extraño como los globales, donde ambos podrían ser ciertos, generalmente, declarar una variable con var ao let asignifica que no hay ninguna thisque le permita acceder acomo una propiedad como su código asume. Entonces, su código aparentemente está asumiendo algo extraño de variable global. Por ejemplo, su código no funciona en node.js y no en modo estricto dentro de una función. Debe especificar las circunstancias exactas donde funciona y probablemente explicar por qué funciona. De lo contrario, es engañoso.
jfriend00
@ jfriend00 bien seguro. No estoy seguro de que agregaría mucho más valor en combinación con el otro ya responde. Actualizará la respuesta
jontro
14
La pregunta era, ¿podría esto "alguna vez" ser verdad? Y la respuesta es sí, y este es uno de los escenarios en los que podría ser cierto: ano es una variable local y se define en el ámbito global con un captador creciente.
Zac Delventhal
190

Esto es posible en el caso de que las variables asean accedidas, digamos 2 trabajadores web a través de SharedArrayBuffer, así como algún script principal. La posibilidad es baja, pero es posible que cuando el código se compila en código máquina, los trabajadores web actualizan la variable ajusto a tiempo para que se cumplan las condiciones a==1, a==2y a==3se satisfacen.

Este puede ser un ejemplo de condición de carrera en un entorno de subprocesos múltiples proporcionado por los trabajadores web y SharedArrayBuffer en JavaScript.

Aquí está la implementación básica de lo anterior:

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)

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

En mi MacBook Air, sucede después de alrededor de 10 mil millones de iteraciones en el primer intento:

ingrese la descripción de la imagen aquí

Segundo intento:

ingrese la descripción de la imagen aquí

Como dije, las posibilidades serán bajas, pero dado el tiempo suficiente, llegará a la condición.

Sugerencia: si tarda demasiado en su sistema. Intenta solo a == 1 && a == 2y cambia Math.random()*3a Math.random()*2. Agregar más y más a la lista reduce la posibilidad de golpear.

mehulmpt
fuente
50
Honestamente, esta es la mejor respuesta. Todas las otras respuestas requieren un intento deliberado de hacer algo profundamente poco intuitivo. Esta respuesta en realidad refleja algo que podría suceder en el mundo real: una condición de carrera.
Tom Swirly
34
No solo eso: he visto que esto sucede en el mundo real. No con la condición exacta en la pregunta, pero ciertamente con la comprobación (a == 1) al comienzo de una función y (a == 2) más adelante en la función, y que el código golpee ambas condiciones. Para su información, la primera vez que vi que esto sucedía fue en un controlador de motor de automóvil, y establecimos estándares de codificación. La segunda vez fue en un sistema dispensador de paja y bengalas para aviones militares, y en mi primer día en la compañía encontré esto y lo arreglé, mientras el resto del equipo aún discutía el problema. (Nivel de felicitaciones: ¡alto! :)
Graham
38
Entonces, ¿ha trabajado en "controladores de motor de automóvil" y "sistemas dispensadores de chaff y bengalas" que están programados en javascript con trabajadores web? No creo que vaya a salir de nuevo.
psaxton el
12
@psaxton :) Por supuesto que no, pero tenemos un software multiproceso con datos compartidos. Este es un antipatrón para todo el software multiproceso, no específico de Javascript o de los trabajadores web. No importa si está programando en lenguaje ensamblador, Brainf * ck, Visual BASIC, C o Javascript; si lo hace con datos compartidos en una aplicación multiproceso, siempre fallará.
Graham el
44
Creo que esto es ahora una envoltura elaborada en torno a la respuesta de @ jontro.
qntm
148

Esto también es posible utilizando una serie de captadores de autoescritura:

(Esto es similar a la solución de jontro, pero no requiere una variable de contador).

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

Patrick Dark
fuente
61
Tenga en cuenta que el enfoque de usar un getter también funciona ===, no solo ==.
Makyen
Esta solución se basa en thisser el objeto global dentro del cuerpo de la función de flecha.
Roy Tinker el
@ Middightas No categorizaría ninguna otra respuesta como "código piramidal" .
Patrick Roberts el
Tenga en cuenta que esto también funciona con un orden arbitrario, ¿no? Al igual que, (a == 3 && a == 2 && a == 1)?
Johannes
131

Alternativamente, puede usar una clase para ello y una instancia para la verificación.

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

var a = new A;

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

EDITAR

Usar clases de ES6 se vería así

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

Nina Scholz
fuente
55
solo function A() {value = 0;al principio?
Dave C
valueOfse está anulando, this method is usually called automatically by JavaScript behind the scenes, and not explicitly in codepor lo que cuando comparamos el valor en realidad aumenta a ...
Danyal Sandeelo
130

No veo esta respuesta ya publicada, así que también incluiré esta en la mezcla. Esto es similar a la respuesta de Jeff con el espacio Hangul de ancho medio.

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

Puede notar una ligera discrepancia con el segundo, pero el primero y el tercero son idénticos a simple vista. Los 3 son caracteres distintos:

a- Minúscula latina A
- Minúscula latina de ancho completo A
а - Minúscula cirílica A

El término genérico para esto es "homoglifos": diferentes caracteres unicode que tienen el mismo aspecto. Por lo general, es difícil obtener tres que sean completamente indistinguibles, pero en algunos casos puedes tener suerte. A, Α, А, y Ꭺ funcionaría mejor (latín-A, alfa griega , cirílico-A , y Cherokee-A , respectivamente; por desgracia, el griego y Cherokee letras minúsculas son demasiado diferentes del latín a: α, , y así doesn No ayudes con el fragmento anterior).

Hay toda una clase de ataques de homoglifos, más comúnmente en nombres de dominio falsos (por ejemplo, wikipediа.org(cirílico) vs wikipedia.org(latino)), pero también puede aparecer en el código; normalmente se las conoce como poco claras (como se menciona en un comentario, las preguntas [poco claras] ahora están fuera de tema en PPCG , pero solían ser un tipo de desafío donde aparecían este tipo de cosas). Usé este sitio web para encontrar los homoglifos utilizados para esta respuesta.

Draco18s ya no confía en SE
fuente
19
"Ligera discrepancia" no es como yo llamaría eso.
44
@hvd depende completamente de la representación de su fuente. Esto es lo que veo .
Draco18s ya no confía en SE
1
@Jake Sí, la letra minúscula latina de ancho completo A no es el mejor homoglifo (pero las variantes en mayúscula son increíbles). Generalmente, aunque solo necesitas dos para obtener el efecto deseado.
Draco18s ya no confía en SE
@ Draco18s Acordado de nuevo: generalmente solo se necesitan 2. Buen trabajo en la información extra también!
JakeSteam
10
También puede usar el selector de variante unicode (U + FE00..U + FE0F). Ninguno de estos son a: a︀ a︁ a︂. No más preocuparse por las discrepancias.
Salman A
108

¡Sí, es posible! 😎

»JavaScript

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

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

El código anterior es una versión corta (gracias a @Forivin por su nota en los comentarios) y el siguiente código es 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 solo ves la parte superior de mi código y lo ejecutas, dices WOW, ¿cómo?

Así que creo que es suficiente decir que sí, es posible para alguien que te dijo: Nada es imposible

Truco: Utilicé un personaje oculto ifpara hacer una función similar a su nombre if. En JavaScript no podemos anular las palabras clave, así que me vi obligado a usarlo de esta manera. Es falso if, ¡pero te funciona en este caso!


»» C #

También escribí una versión de C # ( con una técnica de aumento del valor de la propiedad ):

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

Demo en vivo

RAM
fuente
56
La versión de JavaScript es un verdadero crimen contra la humanidad y la capacidad de hacerlo debería ser ilegal según las convenciones de la ONU. Creo que es hora de que purguemos al mundo de todo el conocimiento de Javacript.
Más claro
2
La declaración de la función podría ser aún más corta. if‌=()=>!0
Forivin
44
¿Por qué demonios usaste document.write? Esa es una forma segura de no ser contratado, independientemente del resto de la respuesta.
Cerbrus el
3
@Cerbrus, gracias por tu nota. Primero escribí mi respuesta con console.logpero la cambié a document.write. Realmente siempre lo uso console.logen mis códigos, pero aquí solo quiero mostrar un texto a los usuarios en el cuadro de fragmentos de código de StackOverflow. Así que quería mostrar mi mensaje más hermoso que el mensaje generado por console.log. Haga clic en el Run Code Snippetbotón en mi respuesta y en otras respuestas. El fragmento de código SO me permitió usar html y JS y CSS, luego quise usarlo en mi respuesta y hacerlo agradable. Creo que no tiene ningún efecto secundario negativo y no hizo que mi respuesta fuera grande o completa.
RAM
1
@Clearer, si las convenciones de la ONU pudieran cambiar el mundo de manera efectiva, entonces deberíamos tener un mundo mejor que este. Necesitamos algo más que una declaración en la ONU y hasta ese día creo que podemos usar este truco de Javascript mío;)
RAM
97

JavaScript

a == a +1

En JavaScript, no hay enteros sino soloNumber s, que se implementan como números de coma flotante de doble precisión.

Significa que si un Número aes lo suficientemente grande, puede considerarse igual a tres enteros consecutivos:

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

Es cierto, no es exactamente lo que preguntó el entrevistador (no funciona con a=0 ), pero no implica ningún truco con funciones ocultas o sobrecarga del operador.

Otros idiomas

Como referencia, hay a==1 && a==2 && a==3soluciones en Ruby y Python. Con una ligera modificación, también es posible en Java.

Rubí

Con una costumbre ==:

class A
  def ==(o)
    true
  end
end

a = A.new

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

O un aumento a:

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

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

Pitón

class A:
    def __eq__(self, who_cares):
        return True
a = A()

if a == 1 and a == 2 and a == 3:
    print("Don't do that!")

Java

Es posible modificar el Integercaché de 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.");
        }
    }
}
Eric Duminil
fuente
27
@ cᴏʟᴅsᴘᴇᴇᴅ: Java, Javascript, potayto, potahto :) Ya hay suficientes respuestas buenas de JS. Simplemente pensé que sería interesante mostrar cómo se puede hacer en otros idiomas, y posiblemente dar algunas ideas a los desarrolladores de JS.
Eric Duminil
2
@ cᴏʟᴅsᴘᴇᴇᴅ: actualizado con un ejemplo de JS.
Eric Duminil
1
¿Por qué la versión Java no funciona con Integer a = 42(o lo hace)? Según tengo entendido, el autoboxing Integer a = 42; a == 1 && a == 2 && a == 3debería encuadrar todas las entradas. ¿O esto unbox un para las comparaciones?
CAD97
@ CAD97: Integer == intparece resultar en unboxing. Pero el uso de Integer#equals(int)fuerzas autoboxing, por lo que funciona. ¡Gracias por el comentario!
Eric Duminil
@StephanBijzitter: Por favor explique. Hasta donde yo sé, solo hay Numbersen JS, que son básicamente como doubles. Pueden parecer enteros y puedes usarlos como enteros, pero aún no son enteros. No creo que n == n + 1pueda ser cierto para los enteros en Java / Python / C / Ruby / ...
Eric Duminil
80

Esta es una versión invertida de la respuesta de @ Jeff * donde se usa un carácter oculto (U + 115F, U + 1160 o U + 3164) para crear variables que se vean como 1, 2y 3.

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

* Esa respuesta se puede simplificar usando un ancho cero sin unión (U + 200C) y un ancho cero (U + 200D). Ambos caracteres están permitidos dentro de los identificadores, pero no al principio:

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

Son posibles otros trucos usando la misma idea, por ejemplo, usando selectores de variación Unicode para crear variables que se vean exactamente iguales ( a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

Salman A
fuente
75

Regla número uno de entrevistas; Nunca digas imposible.

No hay necesidad de trucos de personajes ocultos.

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

MonoZeus
fuente
66
Ay. __defineGetter__en realidad no es parte del lenguaje js, solo una versión fea de defineProperty. typeofno es una función y esto no declarado ies simplemente horrible. Todavía parece valer 40 votos a favor: /
Jonas Wilms
66
@JonasW. 41 votos a favor :-) Soy consciente de que __defineGetter__está en desuso por developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… pero se ejecuta claramente en mi FireFox v 57.0.4, así que opté por mostrar esto en lugar de defineProperty()porque el código heredado es real y no se puede ignorar. Independientemente de la fealdad, declarar ide la manera que lo hice es un comportamiento bien conocido / documentado. Tal vez solo estaba de humor PCG ¯ \ _ (ツ) _ / ¯
MonkeyZeus
68

Honestamente, sin embargo, si hay una forma de evaluarlo como verdadero o no (y como otros han demostrado, hay varias formas), la respuesta que estaría buscando, hablando como alguien que ha realizado cientos de entrevistas, sería algo en la línea de:

"Bueno, tal vez sí en un conjunto extraño de circunstancias que no son obvias para mí de inmediato ... pero si me encontrara con esto en un código real, usaría técnicas comunes de depuración para descubrir cómo y por qué estaba haciendo lo que estaba haciendo. e inmediatamente refactorizar el código para evitar esa situación ... pero lo más importante: NUNCA escribiría ese código en primer lugar porque esa es la definición misma de código contorneado, y me esfuerzo por nunca escribir código convolucionado ".

Supongo que algunos entrevistadores se ofenden por tener lo que obviamente debe ser una pregunta muy complicada, pero no me importa que los desarrolladores tengan una opinión, especialmente cuando pueden respaldarla con un pensamiento razonado y pueden encajar mi pregunta en Una declaración significativa sobre ellos mismos.

Frank W. Zammetti
fuente
13
La pregunta (o todas las preguntas de la entrevista) probablemente sea para evaluar la disposición de los candidatos a pensar en un problema, especialmente los que son "aparentemente obvios", como este. Alguien que se niega a pensar porque cree que "sabe" que la respuesta no es una buena contratación.
Shammoo
55
@Don Hatch No, no los penalizaría si respondieran de buena fe y especialmente si daran una respuesta correcta como las que otros han demostrado ... pero luego pediría un seguimiento para tratar de probar si creen que es Una buena manera de escribir código o no. Estar bien informado y poder dar una respuesta "correcta" es solo una parte de ser un buen desarrollador. Mucho más importante para un desarrollador "profesional" es escribir código que sea comprensible y mantenible en el futuro, a menudo por desarrolladores menos capaces. Los desarrolladores demasiado inteligentes son tan malos como los incapaces de IME.
Frank W. Zammetti
16
Esto no responde la pregunta.
TylerH
66
Lo triste de esta respuesta es que un usuario de 1rep respondió eso ayer y recibió 2 votos negativos que le hicieron eliminar esta pregunta.
Jonas Wilms
8
@JohnColeman, la pregunta pregunta cómo podría evaluarse el código como verdadero. No pregunta las razones por las cuales el entrevistador propuso la pregunta en primer lugar. Esta respuesta ni siquiera intenta abordar la pregunta que se hace, sino que se centra por completo en una versión de "lo que haría" de un intento de adivinar cuál era el propósito del entrevistador. Si esa fuera la pregunta, sería demasiado amplia. Por lo tanto, esta respuesta no pertenece aquí ni en ninguna parte del sitio.
TylerH
43

Si alguna vez recibe una pregunta de entrevista (o nota un comportamiento igualmente inesperado en su código) piense en qué tipo de cosas podrían causar un comportamiento que parece imposible a primera vista:

  1. Codificación : en este caso, la variable que estás viendo no es la que crees que es. Esto puede suceder si intencionalmente juega con Unicode usando homoglifos o caracteres de espacio para hacer que el nombre de una variable se parezca a otra, pero los problemas de codificación también pueden introducirse accidentalmente, por ejemplo, al copiar y pegar código de la Web que contiene código Unicode inesperado puntos (p. ej., porque un sistema de gestión de contenido realizó un "formateo automático", como reemplazarlo flcon 'LATIN SMALL LIGATURE FL' (U + FB02) de Unicode).

  2. Condiciones de carrera : puede ocurrir una condición de carrera , es decir, una situación en la que el código no se ejecuta en la secuencia esperada por el desarrollador. Las condiciones de carrera a menudo suceden en código de subprocesos múltiples, pero no se requieren múltiples subprocesos para que las condiciones de carrera sean posibles: la asincronía es suficiente (y no se confunda, async no significa que se usen múltiples subprocesos debajo del capó ).

    Tenga en cuenta que, por lo tanto, JavaScript tampoco está exento de condiciones de carrera solo porque es de un solo subproceso. Vea aquí un ejemplo simple de un solo subproceso, pero asíncrono. Sin embargo, en el contexto de una sola declaración, la condición de carrera sería bastante difícil de alcanzar en JavaScript.

    JavaScript con los trabajadores web es un poco diferente, ya que puede tener múltiples hilos. @mehulmpt nos ha mostrado una gran prueba de concepto utilizando trabajadores web .

  3. Efectos secundarios : un efecto secundario de la operación de comparación de igualdad (que no tiene que ser tan obvio como en los ejemplos aquí, a menudo los efectos secundarios son muy sutiles).

Este tipo de problemas puede aparecer en muchos lenguajes de programación, no solo en JavaScript, por lo que no estamos viendo uno de los clásicos WTF de JavaScript clásicos aquí 1 .

Por supuesto, la pregunta de la entrevista y las muestras aquí parecen muy artificiales. Pero son un buen recordatorio de que:

  • Los efectos secundarios pueden volverse realmente desagradables y un programa bien diseñado debe estar libre de efectos secundarios no deseados.
  • El estado de subprocesamiento múltiple y mutable puede ser problemático.
  • No realizar correctamente la codificación de caracteres y el procesamiento de cadenas puede provocar errores desagradables.

1 Por ejemplo, puede encontrar un ejemplo en un lenguaje de programación totalmente diferente (C #) que exhibe un efecto secundario (uno obvio) aquí .

Dirk Vollmar
fuente
1
Entonces, la pregunta se vuelve demasiado amplia. Diferentes idiomas pueden implementar esto con diferentes grados de facilidad. La pregunta ha ganado mucha tracción porque es un Q&A específico de JS, pero ese es solo mi 2c.
cs95
1
Las causas son diferentes C # y JavaScript, por lo que esta respuesta no es legítima
Edwin
3
@Edwin: Las causas son exactamente las mismas: Unicode jugando con glifos o caracteres espaciales de aspecto similar, condiciones de carrera o efectos secundarios de la operación de comparación (este último se muestra en mi ejemplo).
Dirk Vollmar
2
@ cᴏʟᴅsᴘᴇᴇᴅ: a veces mirar las cosas desde un ángulo más amplio ayuda a ver el problema real.
Dirk Vollmar
3
Desearía que esta respuesta pudiera etiquetarse a esta pregunta de alguna manera "meta". Después de leer todas las respuestas por encima de ella, me dio la sensación que JS tiene por lo muchos agujeros, pero que acaba de resumir todas las respuestas de una sola vez. Y lo hiciste de una manera que convierte esto en una pregunta estelar de entrevista (si se elimina la etiqueta específica del idioma) en mi opinión. ¡Bravo!
KCE
41

Aquí hay otra variación, utilizando una matriz para extraer los valores que desee.

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

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

Teófilo
fuente
31

De acuerdo, otro truco con generadores:

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

BaggersIO
fuente
Dices hackear, pero estoy bastante seguro de que este es el caso de uso de los generadores ... :) (bueno, excepto que esto se basa en thisser el objeto de la ventana)
Cody G
29

Usando 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);

Los proxies básicamente pretenden ser un objeto de destino (el primer parámetro), pero interceptan operaciones en el objeto de destino (en este caso, la operación "obtener propiedad") para que haya una oportunidad de hacer algo que no sea el comportamiento predeterminado del objeto. En este caso, se activa la acción "obtener propiedad" acuando ==coacciona su tipo para compararlo con cada número. Esto pasa:

  1. Creamos un objeto de destino { i: 0 }, donde eli propiedad es nuestro contador
  2. Creamos un Proxy para el objeto de destino y lo asignamos a a
  3. Para cada a ==comparación, ael tipo se coacciona a un valor primitivo
  4. Este tipo de coerción resulta en llamadas a[Symbol.toPrimitive]()internas
  5. El Proxy intercepta obtener la a[Symbol.toPrimitive]función usando el "get handler"
  6. Los cheques de proxy "obtener Handler" que la propiedad que está siendo conseguido es Symbol.toPrimitive, en cuyo caso se incrementa y luego devuelve el contador desde el objeto de destino: ++target.i. Si se recupera una propiedad diferente, simplemente volvemos a devolver el valor de propiedad predeterminado,target[name]

Entonces:

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

Como con la mayoría de las otras respuestas, esto solo funciona con una verificación de igualdad suelta ( ==), porque las verificaciones de igualdad estrictas ( ===) no hacen una coerción de tipo que el Proxy puede interceptar.

IceCreamYou
fuente
2
Sin embargo, no tiene sentido usar un proxy para esto: definir Symbol.toPrimitivede la misma manera en un objeto funcionaría igual de bien.
Ry-
27

En realidad, la respuesta a la primera parte de la pregunta es "Sí" en todos los lenguajes de programación. Por ejemplo, esto es en el caso 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;
}
Gustavo Rodríguez
fuente
27
No creo que sea posible en todos los lenguajes de programación. No todos los idiomas tienen preprocesadores, por ejemplo. Para el caso, no todos los lenguajes usan &&lógico "y".
Keith Thompson el
3
Encontré una forma que funciona tanto en Python como en C ++ que utiliza la sobrecarga del operador.
Pato Donald el
77
Y puede hacerlo en Java utilizando la reflexión y desordenando la memoria caché entera.
CAD97
77
No puedo hacerlo en idiomas que no admitan la mutación en ese lugar, por ejemplo, nada comparable está disponible en Haskell
Jason Carr
44
La pregunta es acerca de JavaScript, no de C ++.
Todos los trabajadores son esenciales el
26

Igual, pero diferente, pero igual (puede ser "probado" varias veces):

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

Mi idea comenzó de cómo funciona la ecuación de tipo de objeto Número.

Preda7or
fuente
44
¡Funciona por segunda vez también!
Salman A
25

Una respuesta ECMAScript 6 que hace uso de símbolos:

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

Debido al ==uso, JavaScript se supone que coaccionan aen algo cerca del segundo operando ( 1, 2, 3en este caso). Pero antes de que JavaScript intente calcular la coerción por sí solo, intenta llamar Symbol.toPrimitive. Si proporciona Symbol.toPrimitiveJavaScript, usaría el valor que devuelve su función. Si no, JavaScript llamaría valueOf.

Omar Alshaker
fuente
24

Creo que este es el código mínimo para implementarlo:

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

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

Crear un objeto ficticio con una costumbre valueOfque incremente una variable global ien cada llamada. 23 personajes!

gafi
fuente
14

¡Éste usa defineProperty con un agradable efecto secundario que causa una variable global!

var _a = 1

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

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

Ben Aubin
fuente
8
podría usar un cierre a: get: (a => () => ++a)(0),no es necesario global.
Nina Scholz
13
@NinaScholz seguro, pero estamos hablando de malas prácticas aquí, solo déjame tener esto: D
Ben Aubin
1

Al anular valueOfuna declaración de clase, se puede hacer:

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

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

const a = new Thing();

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

Lo que sucede es que valueOfse llama en cada operador de comparación. En el primero, aserá igual 1, en el segundo, aserá igual 2, y así sucesivamente, porque cada vez que valueOfse llama, el valor de ase incrementa.

Por lo tanto, console.log se activará y generará (de todos modos en mi terminal) Thing: { value: 4}, lo que indica que el condicional era verdadero.

Jonathan Kuhl
fuente