看到这个标题,很多人可能会感觉很新奇, a == 'juejin' && a == 666 && a == 888
为 true,这怎么可能呢?javascript 有时就是这么的神奇,上面表达式的实现是通过 js 隐式转换部分知识实现的,那让我们先来了解一下隐式转换,再去尝试实现上述表达式吧。
什么是隐式转换
在 javascript 中,当运算符在运算时,如果两边数据类型不统一,CPU就无法进行运算,这时 javascript 会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算。这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换。
当引用类型和基础类型进行运算时,会将引用类型转换为基础类型。在 javascript 中,每个引用类型都有他们的内置方法,其中有两个内置方法 valueOf()
和 toString()
:
- toString(): 返回对象的字符串表示。
- valueOf(): 返回对象对应的字符串、数值或布尔值表示。通常与 toString()的返回值相同。
他们能够将 Object 类型隐式转换为基础类型,从而进行运算和比较。
不同类型转换规则
了解了隐式转换需要将不同类型转换为同一类型,那我们需要在了解一下不同类型转换的规则。
首先 js 目前有基本类型: number、string、boolean、undefined、null和symbol,引用类型为Object。
其中,js规定 undefined == null
,且其他类型无法转换为 undefined 和 null。剩下的其他类型大多可以互相转化。
其他类型 -> number类型
string -> number
- 如果 string 的内容为纯数字内容,则转换结果为数字
- 如果 string 的内容不是纯数字,则转换结果为NaN
Number('1272421') // 1272421
Number('ok111') // NaN
boolean -> number
- true -> 1
- false -> 0
Number(true) // 1
Number(false) // 0
undefined -> number
- undefined -> NaN
Number(undefined) // NaN
null -> number
- null -> 0
Number(null) // 0
Object -> number
- 先调用 valueOf() 方法,看能否得到一个基础类型,如能,使用 Number() 对此基础类型进行转换
- 如调用 valueOf() 没有得到基础类型,则调用 toString() 方法看能否得到一个基础类型,如能,使用 Number() 对此基础类型进行转换;如不能,报错
// 未实现自定义 valueOf() 和 toString() 的对象
const a = { value: 1 }
Number(a) // NaN
// 自定义了 valueOf() 返回基础类型
const b = {
valueOf() {
return 6
}
}
Number(b) // 6
// 自定义了 toString() 返回基础类型
const c = {
toString() {
return 7
}
}
Number(c) // 7
// 自定义了 valueOf() 和 toString() 都不返回基础类型
const d = {
valueOf() {
return {}
},
toString() {
return {}
}
}
Number(d) // Uncaught TypeError: Cannot convert object to primitive value
其他类型 -> string
基础类型 -> string
- 基础类型转换为string,相当于直接在外面
""
变成字符串内容
String(666) // "666"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
Object -> string
- 先调用 toString() 方法,看能否得到一个基础类型,如能,使用 String() 对此基础类型进行转换
- 如调用 toString() 没有得到基础类型,则调用 valueOf() 方法看能否得到一个基础类型,如能,使用 String() 对此基础类型进行转换;如不能,报错
// 未实现自定义 valueOf() 和 toString() 的对象
const a = { value: 1 }
Number(a) // "[object Object]"
// 自定义了 toString() 返回基础类型
const b = {
valueOf() {
return "ok"
}
}
String(b) // "ok"
// 自定义了 valueOf() 返回基础类型
const c = {
toString() {
return "hello"
}
}
String(c) // "hello"
// 自定义了 valueOf() 和 toString() 都不返回基础类型
const d = {
valueOf() {
return {}
},
toString() {
return {}
}
}
String(d) // Uncaught TypeError: Cannot convert object to primitive value
其他类型 -> boolean
- undefined null 0 -0 +0 NaN '' 转换结果为 false
- 其他类型和值转换结果都为 true
Boolean(undefined) // false
Boolean({}) // true
== 比较规则
基础类型的比较
- undefined等于null
- string 和 number 比较时,string 转 number
- number 和 boolean 比较时,boolean 转 number
- string 和 boolean 比较时,两者转 number
undefined == null; //true
'0' == 0; //true,字符串转数字
0 == false; //true,布尔转数字
'0' == false; //true,两者转数字
引用类型和基础类型比较
引用类型和基础类型比较,上面提到过会通过 valueOf() 和 toString() 方法将引用类型转换为基础类型,然后进行比较。上面有提到过转换规则,引用类型转换为 number 类型优先使用 valueOf(),转换成 string 类型优先使用 toString()。
但是在使用 ==
进行比较时有一点区别:
- 和 boolean 类型比较,都转换为 true
- 和 number 或者 string 类型比较,都优先使用 valueOf() 看能否转换为基础类型,能的话将基础类型在转换成对应的 number 或者 string 类型比较;不能的话再使用 toString() 进行转换
实现 a == 'juejin' && a == 666 && a == 888
理解了上面的隐式转换规则,那我们就可以思考如何来实现了。
我们可以自定义 valueOf(),第一次比较时返回的值为 'juejin',第二次为666,之后返回的值为888:
const a = {
count: 0, // 记录当前是第几次比较
valueOf() {
this.count++;
if(this.count === 1) {
return 'juejin'
} else if(this.count === 2) {
return 666
} else {
return 888
}
}
}
console.log(a == 'juejin' && a == 666 && a == 888) // true
如此就实现了标题中的表达式为 true。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!