Future&Hope

js中由运算符引发的隐式转换

一元正号(+)

一元正号运算符(unary plus operator)位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转换成一个数值。它可以将字符串转换成整数和浮点数形式,也可以转换非字符串值 truefalse null。小数和十六进制格式字符串也可以转换成数值。如果它不能解析一个值,则计算结果为 NaN.

一元加号会将后面跟着的表达式全部转换成数字

1
2
3
4
5
+3 // 3
+"3" // 3
+true // 1
+false // 0
+null // 0

然后这里有个地方需要注意,就是如果+号后面跟着的是对象。这时候会触发对象到数字的转换。根据犀牛书,对于关系运算符,所有的对象都是先调用valueOf方法,再调用toString方法(除了日期类,因为日期类调用valueOf直接得到1970年至今的毫秒数)。但是如果手动修改了对象的valueOf方法,则不会再调用toString。具体如下:

1
2
3
4
5
var obj = {
toString: function() { return "Object CustomObj"; },
valueOf:function() { return 1; }
};
+obj // 1
1
2
3
4
5
6
7
8
9
10
var obj = {
toString: function() { return "Object CustomObj"; },
valueOf:function() {
console.log('valueOf is called ');
return Object.prototype.valueOf.apply(this);
}
};
+obj
// valueOf is called
// NaN

通过第二个例子我们可以看到一元加号是先调用了valueOf再调用toString方法的。

二元加号

加法运算符(addition operator)的结果是数值求和,或者字符串拼接。

二元加号的两侧如果没有字符串的话,会隐式的将两个操作符都转换成数字,如果遇到字符串就将另一个操作符转换成字符串。根据这个回答有一点需要注意,两个操作符都会被转换成原始值,所以在进行转换的时候已经进行了valueOf的调用。

==比较

==比较也是一个会涵盖很多隐式转换的操作符。==比较遵从以下4个规则:

  • 当比较数字和字符串时,字符串会转换成数字值。 JavaScript 尝试将数字字面量转换为数字类型的值。 首先, 一个数学上的值会从数字字面量中衍生出来,然后得到被四舍五入后的数字类型的值。
  • 如果其中一个操作数为布尔类型,那么布尔操作数如果为true,那么会转换为1,如果为false,会转换为整数0,即0。
  • 如果是一个对象与数字或字符串向比较,JavaScript会尝试返回对象的默认值。操作符会尝试将对象转换为其原始值(一个字符串或数字值)通过方法valueOf和toString。如果尝试转换失败,会产生一个运行时错误。
  • 注意:当且仅当与原始值比较时,对象会被转换为原始值。当两个操作数均为对象时,它们作为对象进行比较,仅当它们引用相同对象是返回true。

注意: 字符串对象的类型是对象,不是字符串

所以会出现以下结果:

1
2
3
4
5
var a = new String('foo');
var b = new String('foo');
a == b //false 因为a,b都是对象,而且他们指向的引用不是同一个,只是值相同。
a == 'foo' // true 因为在比较之前,a已经已经做了toString的转换

To Be Continued…