Recientemente, me hicieron una pregunta muy interesante en una entrevista: ¿Puede (a== 1 && a2 && a3) evaluarse como verdadero en JavaScript? Casi pierdo la oportunidad de trabajo porque no pude responder.

En ese momento, me sorprendió la pregunta y pensé que èl entrevistador estaba bromeando.

Pero cuando vi su "sonrisa", un sentimiento de "no debes saber la respuesta" cruzó por mi mente. Definitivamente no era un problema fácil de resolver.

El artículo dará 6 respuestas profesionales. Empecemos de inmediato.

Solución 1: valueOf && toString


La primera solución es muy sencilla, y estoy seguro de que te harás una idea una vez que hayas leído este código.

let a = {
  name: 'fatfish',
  toString () {
    return 'medium'  
  }  
}

// My friends, will "hello medium" be printed out?
if (a == 'medium') {
  console.log('hello medium')  
}

Es increíble, ¿qué está pasando? No te preocupes, amigo, intentaré explicarte por qué.

Explicando parte de las reglas de conversión implícitas
Cuando se utiliza == para comparar dos valores en JavaScript, se realizan las siguientes operaciones:

  1. Convertir los dos valores comparados al mismo tipo.
  2. Después de la conversión (uno o ambos lados de la ecuación pueden ser convertidos), comparar los valores.


Las reglas de comparación se muestran en la siguiente tabla:

De la tabla se puede obtener alguna información.

Para que (a == 1), a sólo puede ser este tipo de situaciones:

El tipo de a es String y se puede convertir al número 1 ('1' == 1 => true).
El tipo de a es Booleano y puede convertirse en el número 1 (true == 1 => true).
El tipo de a es Object y puede ser convertido al número 1 a través del "mecanismo de conversión".

"Mecanismo de conversión" del objeto al tipo original


Las reglas 1 y 2 no tienen nada de especial. Veamos la 3:

  1. Cuando el objeto se convierte al tipo original, se llama a la función incorporada [ToPrimitive]. La lógica es aproximadamente la siguiente:
  2. Si hay un método Symbol.toPrimitive, llamarlo primero, en caso contrario
    Llamar a valueOf, si se puede convertir al tipo original, devolver, en caso contrario
  3. Llamar a toString, si se puede convertir al tipo original, devolver, en caso contrario
  4. Si no se devuelve el tipo original, se informará de un error.
const obj = {
  value: 1,
  valueOf() {
    return 2
  },
  toString() {
    return '3'
  },
  [Symbol.toPrimitive]() {
    return 4
  }
}
obj == 4 // true
// You can comment out the "symbol. Toprimitive", "toString" and "valueof" methods respectively to verify whether the conversion rules are effective
view rawSymbol.toPrimitive.js hosted with ❤ by GitHub

Amigo, gracias por ser muy paciente y leer durante mucho tiempo y estoy seguro de que tienes la respuesta en tu mente.

let a = {
  i: 1,
  // Replacing valueof with toString has the same effect
  // toString
  valueOf() {
    return this.i++
  }
}
if (a == 1 && a == 2 && a == 3) {
  console.log('hello medium') // hello medium
}

Solución 2: Array && join


La conversión implícita de objetos array también cumple con la regla 3, pero el método 'join' será llamado antes que "toString". Así que puedes empezar por aquí.

let a = [1, 2, 3]

a.join = a.shift

if (a == 1 && a == 2 && a == 3) {
  console.log('hello medium') // hello medium
}

Solución 3: Utilizar el operador "with


MDN tiene una advertencia sobre el uso de with, como si su existencia fuera un error. Nunca lo he utilizado en mi trabajo, pero se puede utilizar para resolver este problema.

let i = 1
with ({
  get a() {
    return i++
  }
}) {
  if (a == 1 && a == 2 && a == 3) {
    console.log('hello medium') // hello medium
  }
}

Eres tan inteligente que no necesitas que te explique lo que significa el código.

Solución 4: Symbol.toPrimitive


Podemos utilizar la regla de conversión implícita 3 para completar la pregunta (¡después de leer la respuesta, sabrás por qué!).

const a = {
  i: 1,
  [Symbol.toPrimitive]() {
    return this.i++
  }
}
// Each time 'a = = xxx' is executed, the "Symbol.toPrimitive" function will be passed first. Naturally, the effect of increasing a in turn can be realized.
if (a == 1 && a == 2 && a == 3) {
  console.log('hello medium') // hello medium
}

El secuestro de datos también es una salida


A través de la conversión implícita, hemos hecho 3 respuestas que hacen que a == 1 && a == 2 && a == 3 retornen true, seguro que has pensado en otra respuesta, el secuestro de datos (data hijacking), el gran Vue Lo hemos utilizado para ganarnos el corazón de millones de desarrolladores, y también intentamos utilizarlo para resolver esta pregunta de la entrevista.

Solución 5: Object.defineProperty


Secuestrando el objeto window, cada vez que se lee el atributo a, el _ a añade 1.

let _a = 1
Object.defineProperty(window, 'a', {
  get() {
    return _a++
  }
})
if (a == 1 && a == 2 && a == 3) {
  console.log('hello medium') // hello medium
}

Solución 6: Proxy


Hay otra forma de secuestrar datos, Vue3 también ha sustituido Object.defineProperty por Proxy.

let a = new Proxy({ i: 1 }, {
  get(target) {
    return () => target.i++
  }
})
if (a == 1 && a == 2 && a == 3) {
  console.log('hello medium') // hello medium
}

Finalmente
Gracias por leer. Espero que sigas y leas más artículos de alta calidad.

Fuente

Plataforma de cursos gratis sobre programación