从一道 js 面试题说下类型转换
1,题目
a
在什么情况下会执行输出语句,打印 ok ?
if (a == 1 && a == 2 && a == 3) {
console.log('ok')
}
2,解决
解决的方法有很多,这里主要讨论下类型转换的问题。更多的解决办法放到文章最后了。
2.1,数据类型转换
分为显示转换和隐式转换。
显示转换又称为强制转换,隐式转换又称为自动转换。
显示转换主要指:通过 Number()
,String()
,Boolean()
手动将不同类型的值分别转为数字,字符串或布尔。
Number()
的参数需要分为2种情况讨论,一种是基本类型,一种是对象。
基本类型值:比较特殊的就是这3种:
Number('324abc') // NaN
Number(undefined) // NaN
Number(null) // 0
其中将字符串转为数值,Number()
的规则是只要有一个字符无法转为数字,那整个字符串就会被转为NaN
。而parseInt()
是逐个分析。
parseInt('123 cats') // 123
Number('321 cats') // NaN
对象:转换规则如下:
-
调用对象自身的
valueOf
方法。如果返回原始类型值,则直接对该值使用Number()
,不再进行后续步骤。 -
如果
valueOf
方法返回的还是对象,则改为调用对象自身的toString
方法。如果toString
方法返回原始类型的值,则对该值使用Number()
,不再进行后续步骤。 -
如果
toString
方法返回的是对象,就报错。
我们来验证下:
const num = Number({
valueOf() {
return 2
},
toString() {
return 3
}
})
console.log(num) // 2
const num = Number({
valueOf() {
return {}
},
toString() {
return 3
}
})
console.log(num) // 3
const num = Number({
valueOf() {
return {}
},
toString() {
return {}
}
})
console.log(num) // TypeError: Cannot convert object to primitive value
所以
Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
String()
和 Number()
相比,会先调用 toString()
,而不是 valueOf()
。
Boolean()
的转换规则比较简单,除了下面6个,其他都是true
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(false) // false
2.2,比较运算
更详细的参考:如何正确比较 - MDN
比较运算符分为两类:相等比较和非相等比较。两者的规则是不一样的。
<
,<=
,>
,>=
,!=
,!==
属于非相等比较运算符。==
===
属于相等比较运算符。
比较算法:
对非相等比较来说,算法是先看2个操作数是否都是字符串,如果是,就按照字典顺序比较(Unicode 码);否则将2个操作数都转成数值来比较大小。
对相等比较来说,
- 严格相等运算符
===
比较的是是否为“同一个值”,而如果2个值不是同一类型,则直接返回 false。 - 相等运算符
==
会将它们先转换成同一个类型,再用严格相等运算符比较。- 如果操作数都是基本类型,则都转为数值进行比较。
- 如果操作数之一是对象,而另一个是原始值,则将对象转为基本类型再进行比较(转换规则和使用
Number()
转对象一致)。
3,解决
const a = {
i: 1,
valueOf() { // 这里用 toString 也可以。
return this.i++;
}
}
if(a == 1 && a == 2 && a == 3) {
console.log('ok');
}
3,其他的解法
1,利用数组的 toString()
a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);
Array.prototype.toString() - MDN
简单来说,Array 覆盖了对象的toString()
,并且在调用 toString()
时内部又调用了join()
。所以可修改join()
方法来实现其他目的。
同样的,数组在比较时也会调用toString()
来转为基本类型。
2,Object.defineProperty
let index = 0;
Object.defineProperty(window, 'a', {
get: function() {
return ++index;
}
});
if (a == 1 && a == 2 && a == 3) {
console.log('ok');
}
3,隐藏空格
注意,a 的左右隐藏着特殊的空格(String.fromCharCode(65440)
)。代码复制到 vscode 中可明显看出不是普通空格。
var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
console.log("ok")
}
以上。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!