2022/1/7更新
神奇的一题,记录一下——
输出是—— tostr tostr true
历程如下:
【1】➖优先执行 等号右边相当于
Number(obj)-1
=1(同时发生隐式类型转换 b自减)-1
=0【2】之后执行等号左边与等号右边的判等操作 相当于
Number(obj)==0
相当于0(同时发生隐式类型转换 b自减)==0
结果自然为true【3】发生了隐式类型转换 b=-1
1.来自某四字大厂的一道面试题
前段时间网上冲浪,看到一道很奇怪的面试题
if ([] == false) {
console.log(1);// 1
}
if ([]) {
console.log(3);// 3
}
if ({} == false ) {
console.log(2);// undefined
}
if ({}) {
console.log(2);// 2
}
if ([1] == [1]) {
console.log(4);// undefined
}
第一眼我是懵的,后来再一想,嗷,隐式转换
再转念一想,现在哪儿还有==
啊,这都是大鹏的瓜,不都用===
嘛?
再再转念一想,基础知识这东西,面试他要用啊。那还等啥,学吧。
2.隐式转换基础知识
读一下红宝书~复习下隐式类型转换的基础知识。
红宝书原文
篇幅并不长,但是十分全面,下面来好好分析下~
对操作数进行类型转换时的规则
a == b;// == 两边的操作数a b进行类型转换时遵循如下规则:
- a为布尔值则将其转换为数值再与b比较,false 转换为 0,true 转换 为 1
- a为字符串,b为数值,则将字符串转换为数值,再与b进行比较
- a为对象,b不是对象,则调用valueOf()方法取得原始值,然后再根据前面的规则进行比较(如果valueOf方法返回的值不是原始值,就调用toString方法)
进行比较时操作符遵循的规则
-
null == undefined
-
null & undefined 不能转换为其他类型的值再进行比较
-
有任一操作数为 NaN 则相等操作符会返回true
- 如果两个操作数a和b都是对象,则需要比较它们是不是同一个对象,如果都指向同一个对象,则相等操作符返回true,否则不相等。
3.面试题解析
看完基础知识,来解析下最上面那道题
【1/3】
if ([] == false) {
console.log(1);// 1
}
if ({} == false ) {
console.log(2);// undefined
}
- [] 与 false 都会转换为0
- {}会被转换为NaN 所以不相等
【2/4】这里很明显不是强制类型转换的内容,而是if语句条件的问题
if ([]) {
console.log(3);// 3
}
if ({}) {
console.log(2);// 2
}
来看看红宝书怎么说:
这样就能解释得通这两题了!
【5】
if ([1] == [1]) {
console.log(4);// undefined
}
就很简单了~上面的基础知识有提到这一点
两个对象的地址值是不同的~
4.写在后面
本文的思考只是针对上面提到的这个面试题,还有很多偏难怪的问法没有涉及到,建议去多看一些其他的题来保证在面试中不会被问倒!
另外我在面试中碰到的隐式转换相关问题也会及时总结进来!保证知识的新鲜程度😂
这里列举几篇我看到的非常出色的相关文章,里面题目会丰富/全面很多,大家可以加加餐——
-
很全面很系统的一篇!从一道面试题说起—js隐式转换踩坑合集
感兴趣的朋友们可以点开前两篇读来看看(第三篇题很多,但是总结得不太系统),感受下JavaScript的这个“坑”。然后再去看看第三篇的题是否都可以理解🧐
再说一个有趣的点——
上面这三篇文章都不约而同地提到了同一道面试题
超级高频强制类型转换面试题
可见其重要程度!
var a = {
i:1,
valueOf:function(){
return a.i++;// this.i++;
}
}
if(a == 1 && a == 2 && a == 3){
console.log("每次进行相等运算都会调用一次a(对象)的valueOf()方法,符合前面提到的转换规则!")
}
再来一题(同理)
var a = {
arr: [1, 666],
i: 0,
valueOf:function(){
return this.arr[this.i++];
}
}
console.log(a == 1 && a == 666);// true
21/11/18 来拓展一个很类似的
参考链接 数据劫持|数据代理
什么样的 a 可以满足 (a === 1 && a === 2 && a === 3) === true 呢?(注意是 3 个 =,也就是严格相等)???
这就跟隐式类型转换无关了——这个是使用
Object.defineProperty()
(Vue2.x同样用这个方式实现双向绑定,Vue3.x使用的是ES2016中的代理Proxy) 完成数据劫持的操作!
Object.defineProperty(window, 'a', { get () { current++ return current } }) console.log(a === 1 && a === 2 && a === 3) // true
说了这么多,来总结一下对象的强制类型转换流程!
对象的强制类型转换流程总结
【1】调用valueOf()方法,是原始值类型就返回,不是就继续下一步
【2】调用toString()方式,是原始值类型就返回,不是就继续下一步
【3】调用Number,是原始值就返回,不是就报类型错误(也只有undefined大神会这样了😂Number(undefined);//NaN
Number(null);//0
)
举个例子
var b = {
toString:function(){
return this.i = 10;// this.i++;
}
}
if(b == 10){
console.log("只有valueOf()返回值不是原始值类型的时候才会动用toString方法")
}
好吧这个是我总结的来着,红宝书上没有写,但是我认为理应如此,证据如下:
可以看到 []
经过隐式类型转换是与 0 相等的
就是因为最后这一步 Number()!