在介绍强制转换之前,不论是显式的还是隐式的,我们需要了解字符串、数字和布尔值之间类型转换的基本规则,这些规则(也叫抽象操作)是仅供内部使用的。
toString
抽象操作toString负责处理非字符串到字符串的强制类型转换。基本类型值得字符串化规则是:null转换成"null",undefined转换为"undefined",true转换成"true"。数字的字符串化则遵循通用规则。
toNumber
抽象操作toNumber处理非数字值到数字值的强制类型转换。规则如下:
true变成1,false变成0,undefined转换成NaN,null变成0- 对字符串的处理基本遵循数字常量的相关规则和语法,处理失败返回
NaN。 - 对象会首先转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
 
为了将值转换为相应的基本类型值,抽象操作ToPrimitive首先通过内部操作DefaultValue检查改制是否有valueOf()方法,如果有并且返回基本类型值,就使用该值进行强制类型转换。如果灭有就使用toString()的返回值来进行强制类型转换。如果两者都没有,产生TypeError错误。
to Boolean
假值,即
undefinednullfalse+0、-0和NaN""
都将强制转换为false。
就算是封装了价值的封装对象,如:
var a = new Boolean(false),
    b = new Number(0),
    c = new String("");
a、b、c的布尔强制转换都是true,因为所有的对象都是真值。
上述三个操作包括toPrimitive就是JavaScript处理类型转换的规则,有了他们,就可以更好地了解强制类型转换。
显式强制类型转换
字符串与数字之间的显式转换
字符串和数字之间的转换是通过String()和Number()这两个内建函数,即原生函数来实现的。
var a = 42,
    b = String(a),
    c = "3.14",
    d = Number(c);
console.log(b); //"42"
console.log(d); //3.14
注意,它们前面没有
new关键字,并不是创建封装对象。但var e = Array(1,2,3)这个语句是构造一个数组对象,new会被自动添加。
String()遵循前面讲的toString规则,Number()遵循前面的toNumber规则。
除了上面的方法外,还有方法可以实现两者的显式转换。
var a = 42,
    b = a.toString(),
    c = "3.14",
    d = +c;
a.toString()是显式的,不过其中涉及隐式转换。因为toString()对象42这种基本类型值不适用,所以会自动为42创建一个封装对象,从而调用toString()方法。值得注意的是,我们没有toNumber()方法。对于d = +c是通过一元运算符显式地将c转换为数字,而非数字加法运算,也不是字符串拼接。至于说这是隐式还是显式,取决于个人理解。如果你知道这是一元运算符的形式,那就是显式。如果你不知道,你说是隐式也没有关系。但在开源社区里,一元运算符+普遍认为是显式。
日期显式转换为数字
一元运算符的另外一个用途是将日期Date对象强制类型转换为数字,返回Unix时间戳,以微秒为单位(即从1970年1月1日00:00:00 UTC到当前时间):
var timestamp = +new Date();
当然,对于提取时间戳我们有更好的方法。
var timestamp = new Date().getTime();
或者使用ES5中新加入的静态方法Date.now()来获取当前的时间戳。
var timestamp = Date.now();
显式解析数字字符串
使用parseInt()方法将字符串解析为整数,parseFloat()方法将字符串解析为浮点数。这和将字符串强制类型转换为数字类似但不同的地方在于,解析允许字符串中含有非数字字符。
var a = "42px";
Number(a); //NaN
parseInt(a); //42
显式转换为布尔值
与前面的String()和Number()一样,Boolean()是显式的toBoolean强制类型转换。
虽然Boolean()是显式的,但并不常用。大家都喜欢使用一元运算符!将值强制转换为布尔值,但同时它也会将假值变为真值,将真值变为假值,所以,你可以使用!!来做判断。
var a = {},
    b = [];
!!a; //true
!!b; //true
在if()语句中,如果没有使用Boolean()和!!,就会自动隐式进行toBoolean转换。
隐式强制类型转换
字符串和数字之间的隐式类型转换
+运算符既能用于数字加法,用能用于字符串拼接。如果+的其中一个操作数是字符串(或者通过一定步骤得到的字符串),则执行字符串拼接操作。
var a = "42",
    b = 0,
    c = [1,2],
    d = [3,4];
a + b; //"420"
c + d; //"1,23,4"
"1,23,4"是怎么来的呢,这就是通过一定步骤得到的字符串。在ES5规则中,如果其中一个操作数是对象(当然包括数组),则首先对其调用toPrimitive抽象操作,该抽象操作再调用[[DefaultValue]]。因为数组的ValueOf()操作无法得到简单的基本类型值,于是它转而调用toString(),因此两个数组变成了"1,2"和"3,4"。+将她们拼接后返回1,23,4。
依上,可以将数字和空字符串""和+来将其转换为字符串。
var a = 42,
    b = a + "";
b; //"42"
a + ""与显式的String(a)的区别在于,a + ""会对a调用valueOf()方法,然后通过toString操作将返回值转换为字符串,而String()则直接调用toString抽象操作。所以,在定制valueOf()和toString()方法时就需要特别小心。
因为-运算符是不会用于字符串操作的,所以可使用-将字符串强制类型转换为数字。
var a = "3.14",
    b = a - 0;
b; //3.14
隐式强制类型转换为布尔值
if()语句的条件判断表达式for(..;..;..)语句中的条件判断表达式while()和do...while()循环中的条件判断表达式?:中的条件判断表达式||、&&左边的操作数
这里特地讲一下||和&&,这与其他语言(C、PHP)中的完全不同。在JavaScript返回值是两个操作数其中的一个。
var a = 42,
    b = "abc",
    c = null;
a || b; //42
c || b; //"abc"
a && b; //"abc"
c && b; //null
||和&&首先会对第一个操作数执行条件判断,如果其不是布尔值就先进行toBoolean强制类型转换,再执行条件判断。
- 
    
对
||来说,如果条件判断结果为true就返回第一个操作数的值,如果为false就返回第二个操作数的值。 - 
    
对
&&来说,刚好相反。判断条件为true就返回第二个操作数的值,如果为false就返回第一个操作数的值。 
所以,基于上述原理,我们有了一种设置默认值的方法,很是方便。
function foo(a,b){
    a = a || "hello";
    b = b || "world";
    console.log(a + " " + b);
}
foo (); // "hello world"
foo ("yeah", "yeah!"); //"yeah yeah!"
&&常用语JavaScript代码压缩工具。
function foo(){
    console.log(a);
}
var a  = 42;
a && foo();
foo()只有在条件判断a通过是才会被调用,如果为通过,a && foo()就会短路,foo()不会被调用。开发人员通常会使用if (a){foo();}这种写法,但压缩工具通常使用a && foo(),因为更简洁。
== vs ===
宽松相等==和严格相等===用来判断两个值是否相等。
正确的解释是:==允许在相等比较中进行强制类型转换,而===不可以。
有些人会认为说
==检查值是否相等,===检查值和类型是否相等。这是不正确的理解。
ES5规范中使用抽象相等比较算法定义了==运算符的行为。
- 如果两个值的类型相同,仅比较他们是否相等
 - 两个对象指向同一值时,即视为相等,不发生强制类型转换
 - 两个不同类型的值是会发生隐式强制类型转换
 
特殊例子有:
NaN不等于NaN,+0不等于-0。
字符串和数字之间的相等比较
ES5规范11.9.3.4-5这样定义:
- 如果
Type(x)是数字,Type(y)是字符串,则返回x == toNumber(y)的结果 - 如果
Type(x)是字符串,Type(y)是数字,则返回toNumber(x) == y的结果 
其他类型和布尔类型之间的相等比较
ES5规范11.9.3.6-7这样定义:
- 如果
Type(x)是布尔类型,则返回toNumber(x) == y的结果 - 如果
Type(y)是布尔类型,则返回x == toNumber(y)的结果 
null和undefined之间的相等比较
ES5规范11.9.3.2-3这样定义:
- 如果
x为null,y为undefined,则结果为true - 如果
x为undefined,y为null,则结果为true 
对象与非对象之间的相等比较
ES5规范11.9.3.8-9这样定义:
- 如果
Type(x)是数字或字符串,Type(y)是对象,则返回x == toPrimitive(y)的结果 - 如果
Type(x)是对象,Type(y)是数字或字符串,则返回toPrimitive(x) == y的结果 
编辑备注:
- 2017-04-17第一次编辑