{}<3表达式的返回值什么< h1>


在看红宝书的时候,测试{}<3时,发生了出乎意料的返回结果…

今天系统重新巩固红宝书,在词法的操作符版块,看到了关系操作符,兴致上来了自己测试了几个用例

1
2
"23" < "3" // true
"a" < 1 // false

我们先来看看红宝书上对该操作符的描述

  • 如果两个操作数都是数值类型,则进行数值比较
  • 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值
  • 如果一个操作数是数值,则将另外一个转化为数值,然后再比较
  • 如果一个操作符是对象,则调用valueOf,用得到的结果按照前面的规则执行比较,如果没有valueOf方法或者返回的值不是基本类型,则用toString方法
  • 如果一个操作数是NaN则返回false,因为NaN不能比较

那么,我们来看一下{}<3这个表达式,3是数值类型,那么我们就对另外一个值操作,先调用valueOf操作,返回{}不是基本数据类型,则调用toString方法,返回”[object Object]”是基本类型,现在变成了一个数值3和一个字符串”[object Object]”进行该操作,我们对字符串进行强制类型转换,转化为NaN,那么实际应该是NaN < 3,返回false才对,但是在chrome浏览器上则是抛出未知语法错误,我就产生了巨大的疑惑,难道是我哪一步推导产生了错误?

打开vsc写了一个脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var o1 = {
valueOf: () => {
console.log("o1 valueOf")
return []
},
toString: () => {
console.log("o1 toString")
return "[object Object]"
}
}
console.log(o1 < 3)
// o1 valueOf
// o1 toString
// false

我自己在这里模拟了一个object,但是为什么在node下就没有报错呢?我又测试了一下更简单直接的版本

1
console.log({} < 3) // false

到这里才恍然大悟,原来之前的语法报错是chrome浏览器自己做的手段,跟ECMAScript规范没有关系

但是也要注意对象在这里的处理情况,并不是对象调用[ToPrimitive]属性直接作为返回值,而是将返回值再带入规则中,可能还要进行第二轮的类型转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var o1 = {
valueOf: () => {
console.log("o1 valueOf")
return "1"
},
toString: () => {
console.log("o1 toString")
return "a"
}
}
var o2 = {
valueOf: () => {
console.log("o2 valueOf")
return 2
},
toString: () => {
console.log("o2 toString")
return 4
}
}

console.log(o1 < o2)
// o1 valueOf
// o2 valueOf
// true

上例中,”1”和2比较,套用规则,再将”1”转换成1之后进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var o1 = {
valueOf: () => {
console.log("o1 valueOf")
return 1
},
toString: () => {
console.log("o1 toString")
return "a"
}
}
var o2 = {
valueOf: () => {
console.log("o2 valueOf")
return "a"
},
toString: () => {
console.log("o2 toString")
return 4
}
}

console.log(o1 < o2)
// o1 valueOf
// o2 valueOf
// false

上例中1和”a”比较,”a”转换为NaN,则返回false