说明
在网上看到的一个面试题:什么时候 a == 1 && a == 2 && a == 3
为 true?
觉得很有趣,记录一下。(当然我想不出来_(:3」∠)_
).
分析
关于要这个表达式成立, a == 1 && a == 2 && a == 3
的每一个条件都要为 true
.
1、显然,如果 每次调用 变量 a ,a 的 值都固定不变,肯定没戏。
2、所以,要想使 a == 1
、a == 2
、a == 3
都为 true
,就是只能每次调用 a 时,a 的 值每次 加 1。
注意:
当两个类型不同时进行 == 比较时,会将一个类型转为另一个类型,然后再进行比较。
1、Object类型与Number类型进行比较时,Object类型会转换为Number类型。
对象转换为 Number
时,会尝试调用 Object.valueOf()
和Object.toString()
来获取对应的数字基本类型。
2、数组调用toString()
会隐含调用Array.join()
方法。
解法一:对象类型转换
1、覆盖自定义对象的 valueOf() 方法
Object.prototype.valueOf()-参考文档
Object 的 valueOf() 方法会返回指定对象的原始值。
不同类型对象的valueOf()方法的返回值。
对象 | 返回值 |
Array | 返回数组对象本身。 |
Boolean | 布尔值。 |
Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。 |
Function | 函数本身。 |
Number | 数字值。 |
Object | 对象本身。这是默认情况。 |
String | 字符串值。 |
Math 和 Error 对象没有 valueOf 方法。 |
代码实现:
var val = 0
var a = {
valueOf: function() {
console.log('valueOf-->', val)
return ++val
}
}
// 分开打印
console.log('Number-->', Number(a))
console.log('Number-->', Number(a))
console.log('Number-->', Number(a))
/* 输出结果:
valueOf--> 0
Number--> 1
valueOf--> 1
Number--> 2
valueOf--> 2
Number--> 3
*/
// 或者直接打印
console.log(a == 1 && a == 2 && a == 3) // 输出:true
2、覆盖自定义对象的 toString() 方法
代码实现:(跟上面的有点类似)
var a = {
i: 1,
toString: function() {
console.log('toString-->', a.i)
return a.i++
}
}
// 分开打印
console.log('Number-->', Number(a))
console.log('Number-->', Number(a))
console.log('Number-->', Number(a))
/* 输出结果:
toString--> 1
Number--> 1
toString--> 2
Number--> 2
toString--> 3
Number--> 3
*/
// 或者直接打印
console.log(a == 1 && a == 2 && a == 3) // 输出:true
代码分析:
object --> number (引用类型转换为原始类型)
- 1、先调用object的
valueOf
方法,如果为原始值,则return,否则第2步 - 2、调用object的
toString
方法,如果为原始值,则return,否则第3步 - 3、抛出
TypeError
异常
如果到这里还是不怎么清晰的话:(请看下图:里面涉及ToPrimitive函数
)
由Dry同学整理提供下图
解法二:数组类型转换
var a = [1, 2, 3];
a.join = a.shift; // 核心操作转移
console.log(a == 1 && a == 2 && a == 3);
// valueOf --> toString --> join
代码分析:
上面代码 a.join = a.shift;
数组 a 的 join 被 shift 方法覆盖。
而数组调用 toString()
会隐含调用 Array.join()
方法。
从而达到一个目的:对数组 [1, 2, 3]
执行 shift
方法操作。
解法三:创建属性 defineProperty 的 get
defineProperty-参考文档
var val = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++val;
}
});
console.log(a == 1 && a == 2 && a == 3);