面试官: (a==1 && a==2 && a==3) 能否在 JavaScript 中为“真”?

开发 前端
最近,我被问到一个非常有趣的面试问题:Can (a== 1 && a==2 && a==3) ever evaluate to true in JavaScript?。 我几乎失去了工作机会,因为我无法回答。

最近,我被问到一个非常有趣的面试问题:Can (a== 1 && a==2 && a==3) ever evaluate to true in JavaScript?。 我几乎失去了工作机会,因为我无法回答。

那一刻,我被这个问题吓了一跳,以为面试官在开玩笑。

但当我看到他的“微笑”时,一种“你一定不知道答案”的感觉掠过我的脑海,这绝对不是一个容易解决的问题。

文章将给出6个专业答案,让我们马上开始吧。

解决方案一:valueOf && toString

第一个解决方案非常简单,相信你在阅读此代码后会有一个想法。

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


if (a == 'medium') {
console.log('hello medium')
}

太神奇了,这是怎么回事? 别担心,我的朋友,我会尽力解释原因。

解释部分隐式转换规则

在 JavaScript 中使用 == 比较两个值时,会执行以下操作:

  • 将两个比较的值转换为相同的类型。
  • 转换后(等式的一侧或两侧可以转换),比较值。

比较规则如下表所示:

图片

从表中可以得到一些信息。 为了使 (a == 1),a 只能是以下几种情况:

  1. a 的类型是 String,可以转换为数字 1('1' == 1 => true)。
  2. a 的类型是布尔值,可以转换为数字 1 (true == 1 => true)。
  3. a的类型是Object,可以通过“转换机制”转换为数字1。

对象到原始类型的“转换机制”

规则 1 和规则 2 没有什么特别之处,我们来看看规则 3:

当对象转换为原始类型时,会调用内置的 [ToPrimitive] 函数。 

逻辑大致如下:

  • 如果有 Symbol.toPrimitive 方法,则先调用。
  • 调用valueOf,如果可以转成原来的类型,则返回。
  • 调用toString,如果能转换成原来的类型,则返回。
  • 如果没有返回原始类型,则会报错。
const obj = {
value: 1,
valueOf() {
return 2
},
toString() {
return '3'
},
[Symbol.toPrimitive]() {
return 4
}
}
obj == 4

我的朋友,感谢你非常耐心地阅读了这么长时间,我相信你心中已经有了答案。

let a = {
i: 1,
valueOf() {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}

解决方案 2:数组 && 连接

数组对象的隐式转换也符合规则 3,但会在“toString”之前调用“join”方法。 所以你可以从这里开始。

let a = [1, 2, 3]


a.join = a.shift


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

解决方案 3:使用“with”运算符

MDN 有一个关于 with 使用的警告,好像它的存在是一个错误。 我在工作中从未使用过它,但它可以用来解决这个问题。

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

你太聪明了,甚至不需要我解释代码的含义。

解决方案 4:Symbol.toPrimitive

我们可以使用隐式转换规则3来完成问题(看完答案你就知道为什么了!)。

const a = {
i: 1,
[Symbol.toPrimitive]() {
return this.i++
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('hello medium')
}

数据劫持也是一种出路

通过隐式转换,我们做了3个答案让a == 1 && a == 2 && a == 3 返回true,你一定想到了另一个答案,数据劫持,伟大的Vue我们用它来赢得人心 数百万开发者,我们也尝试用它来解决这个面试问题。

解决方案 5:Object.defineProperty

通过劫持‘window’对象,每次读取‘a’属性时,_a加1。

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

解决方案 6:代理

还有另一种劫持数据的方式,Vue3 也用 Proxy 替换了 Object.defineProperty。

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

责任编辑:华轩 来源: web前端开发
相关推荐

2024-04-26 12:01:10

ping命令断网

2023-08-13 16:17:31

2022-12-05 14:05:26

MySQL最大取值存储

2023-08-11 17:13:39

JavaScrip

2024-04-23 14:09:59

JavaScript开发

2021-07-15 07:23:25

React动画页面

2020-08-24 10:55:41

数据库双写代码

2022-07-15 08:22:42

对象符串键Symbol

2024-03-26 16:24:46

分布式事务2PC3PC

2022-03-31 16:47:30

mysqlcount面试官

2022-05-23 08:43:02

BigIntJavaScript内置对象

2022-06-29 16:59:21

Vue3Vue2面试

2015-08-13 10:29:12

面试面试官

2021-02-25 07:08:30

JavaScript 前端面试题

2024-03-28 10:37:44

IoC依赖注入依赖查找

2021-03-16 07:13:07

Java对象存储

2024-04-11 13:10:00

Vue3Reactive响应性

2022-02-09 09:37:54

ReactorNettyI/O

2023-02-16 08:10:40

死锁线程

2023-09-26 07:49:11

AOP代理spring
点赞
收藏

51CTO技术栈公众号