聊聊js中什么情况a == 1 && a == 2 && a == 3 为true

98 阅读1分钟

关于 == 和 === 比较操作

  • js中 == 运算符涉及到不同类型的比较,往往会用到很多定义好的隐式转换规则,这大部分的纷繁规则大多数前端开发人员都没办法完全掌握(或者说是没必要). 所以大部分的开发团队都是禁用 == 和 != 运算符,采用 === 和 !== 运算符替代.

原始类型和对象比较

如果原始类型的值和对象进行比较,那么先将对象转换为原始类型的值再与原始类型值比较.对象转换为原始类型的值时js优先调用valueOf方法,如果返回还是对象就再调用toString方法.

  • 列如
const a = {
  toString() {
    console.log('调用toString') // 打印2 调用toString
    return 0
  },
  valueOf() {
    console.log('调用valueOf') // 打印1 调用valueOf
    return {}
  }
}

console.log(a == 0) // 返回true
  • 所以由此可得

方案一

const a = {
  num: 1,
  valueOf() {
    return a.num++
  }
}

console.log(a == 1 && a == 2 && a == 3) // 返回true

方案二


const a = {
  num: 1,
  toString(){
    return a.num++
  },
  valueOf() {
    return {}
  }
}

console.log(a == 1 && a == 2 && a == 3) // 返回true

方案三

array 类型也属于对象,数组调用toString 方法的时候,会调用本身的join(',')方法传入参数',', 所以我们可以有一种巧妙的方法.

const a = [1,2,3]
a.join = a.shift

console.log(a == 1 && a == 2 && a == 3) // 返回true

方案四: 使用Object.defineProperty

let num = 0;
Object.defineProperty(window, 'a', { // 注意非浏览器环境global可能不是window
  get() {
    return ++num;
  }
});
console.log(a == 1 && a == 2 && a == 3) // 返回true

方案五: 使用Symbol.toPrimitive

Symbol.toPrimitive: Symbol.toPrimitive 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。 ES6新增原始类型Symbol,通过Symbol的方法toPrimitive可以有方案.

const a = {
  [Symbol.toPrimitive]: ((num) => () => num++) (1)
}
console.log(a == 1 && a == 2 && a == 3) // 返回true

结束