js中有7种数据类型,可以分为两类:
- 基础类型(原始值):
Undefined
、Null
、String
、Number
、Boolean
、Symbol
(es6新出的) - 复杂类型(对象值):
object
什么情况下能正确打印‘success’?
var a = ???
if(a == 1 && a == 2 && a == 3 ){
console.log('success')
}
- 关系运算符:会把其他数据类型转换成
number
之后再比较关系 - 首先我们排除掉原始数据类型(Undefined、Null、Boolean、Number 和 String、Symbol),a应该是个复杂数据类型
- 复杂数据类型在隐式转换时会利用
valueOf
和toString
,然后再转成Number运算(valueOf和toString是所有对象原型链顶层原型Object.prototype
里的方法,所以每个对象都继承这两方法)
由此得知,我们可以重写复杂数据类型在隐式转换过程中所涉及的方法来达到效果
// 方法1
var a = {
i: 0,
valueOf() { // 这里的valueOf()也可以替换成toString()
return ++this.i
}
}
if(a == 1 && a == 2 && a == 3 ){
console.log('success')
}
// 方法2
var a = {
arr: [3, 2, 1],
valueOf() { // 这里的valueOf()也可以替换成toString()
return this.arr.pop()
}
}
if (a == 1 && a == 2 && a == 3) {
console.log('success')
}
在隐式转换为number
时,执行以下流程:
1、如果当前值已经是一个原始类型,则直接返回它
2、否则,如果当前值是一个对象,则先调用valueOf()方法,如果结果是原始类型则直接返回
3、否则,调用这个对象的toString()方法,如果结果是原始类型,则返回toString()结果
4、否则,抛出TypeError异常
具体隐式转换规则可参考here
- 所以上题在运行时会先判断 a 的类型,此时
typeof a
('object'),不是原始类型,因此会先调用a.valueOf()
- 由于我们重写了
valueOf()
,因此会执行重写后的valueOf()
,每一次都会(得到自增后的值)or(返回a.arr的尾元素,并更新a.arr),结果是原始类型所以不会再继续调用toString()
- 得出三次执行结果为 1, 2, 3, 满足条件
~~欢迎交流指正