实现:(a == 1 && a == 2 && a == 3) === true

前言

这个问题,有取巧的解法,但是当被问到这道题,面试官真正想考察的是你对于隐式转换这个知识点的理解,还有你能否考虑到数据劫持

取巧解法

let i=1;
with({
    
    
	get a() {
    
    
		return i++;
	}
}){
    
    
	if(a==1 && a==2 && a==3) {
    
    
		console.log('哈哈哈,成功了')}
}

隐式转换

js中通过==对两个值进行比较的时候,会做如下操作:

  1. 将两个被比较的值转换为同一类型
  2. 转换后(等式的一边或者两边都可能会被转换),在进行值的比较

最终的比较方式等同于全等操作符=== 的比较方式, 相等操作符满足交换律。
相等操作符对于不同类型的值,进行的比较如下图所示:
在这里插入图片描述
从表中可以得到几点信息为了让(a == 1)a只有这几种:

  1. a类型为String,并且可转换为数字1('1' == 1 => true)
  2. a类型为Boolean,并且可转换为数字1 (true == 1 => true)
  3. a类型为Object,通过转换机制后,可转换为数字1 (请看下文)

对象转原始类型的"转换机制"
规则1和2没有什么特殊的地方,我们来看看3:
对象转原始类型,会调用内置的[ToPrimitive]函数,逻辑大致如下:

  1. 如果有Symbol.toPrimitive方法,优先调用再返回,否则进行2。
  2. 调用valueOf,如果可以转换为原始类型,则返回,否则进行3。
  3. 调用toString,如果可以转换为原始类型,则返回,否则进行4。
  4. 如果都没有返回原始类型,会报错。

解法:

const a = {
    
    
  i: 1,
  [Symbol.toPrimitive]() {
    
    
    return this.i++
  }
}
// 每次进行a == xxx时都会先经过Symbol.toPrimitive函数,自然也就可以实现a依次递增的效果
if (a == 1 && a == 2 && a == 3) {
    
    
  console.log('哈哈哈,成功了') 
}

当然也可以利用valueOftoString

const a = {
    
    
  i: 1,
  valueOf() {
    
    
    return this.i++
  }
}
// 每次进行a == xxx时都会先经过valueOf/toString函数,自然也就可以实现a依次递增的效果
if (a == 1 && a == 2 && a == 3) {
    
    
  console.log('哈哈哈,成功了') 
}

数据劫持

Object.defineProperty, 通过劫持window对象,每次读取a属性时,都给_a 增加1.

Object.defineProperty(window, 'a', {
    
    
	get() {
    
    
		return _a++;
	}
})

那能想到defineProperty自然会想到proxy

let a =  new Proxy({
    
    i:1}, {
    
    
	get(target){
    
    
		console.log(target);
		return () => target.i++
	}
})

三种方式,你学会了吗?

猜你喜欢

转载自blog.csdn.net/weixin_44761091/article/details/123891194