一.值类型之间的数据类型转换:
(1)数字和字符串使用+运算符:
数字和字符串如果使用+运算符进行操作,那么会将数字先转换为字符串,然后进行字符串连接操作:
var antzone = "antzone";
var num = 8;
console.log(antzone+num);//antzone8
(2)布尔值参与的+运算符操作:
如果有布尔型参与,那么首先会将布尔值转换为对应的数字或者字符串,然后再进行相应的字符串连接或者算数运算。
var bool = true;
var num = 8;
console.log(bool + num);//9
上面的代码是先将true转换为数字1,然后再进行算数加运算。
var bool = true;
var str='123';
console.log(bool + str);//true123
上面的代码是先将true转换为字符串‘true’,然后再进行字符串连接运算。
(3)Null和Undefined参与的+运算符操作
如果和数字进行计算,null会转化为0,undefined会转化成NaN
console.log(undefined+1);//NaN
console.log(null+1);//0
首先调用string()方法,取得相应的字符串值再进行操作
var a;
var str='123';
console.log(a + str);//'undefined123'
var a=null;
var str='123';
console.log(a + str);//'null123'
(4)减法操作:
如果一个操作数为string、boolean、null、undefined,则在后台调用Number()函数,将其转换成数值,再进行操作。
如果进行减法操作,那么两个操作数都会先被转换为数字,然后在进行算数运算:
var bool = true;
var num = "8";
console.log(bool - num);//-7
true会被转换为数字1,字符串”8”会被转换为数字8,然后进行算术运算。
注意:Null转换为0,Undefined转换成NaN
var a=null;
var num = "8";
console.log(a - num);//-8
var a;
var num = "8";
console.log(a - num);//NaN
(4)==等性运算:
undefined和null比较特殊,它们两个使用==运算符返回值是true。
console.log(undefined==null);
其他值类型(Number、Boolean、Null、Undefined)进行比较的时候都会将运算数转换为数字
console.log("3"==3);//true
上面的代码会将字符串”3”转换成数字,然后再进行比较。
console.log("1"==true);//true
上面的代码会分别将”1”和true转换成数字,然后进行比较
隐式类型转换,有时候,会隐藏一些错误的,比如,null会转换成0,undefined会转换成NaN。需要注意的是,NaN和NaN是不相等的(这是由于浮点数的精度决定的),如下
var x = NaN;
x === NaN; // false
虽然,JavaScript提供了isNaN来检测某个值是否为NaN,但是,这也不太精确的,因为,在调用isNaN函数之前,本身就存在了一个隐式转换的过程,它会把那些原本不是NaN的值转换成NaN的,如下:
isNaN("foo"); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN({ valueOf: "foo" }); // true
上面代码,我们使用isNaN来测试后,发现字符串,undefined,甚至对象,结果都返回真!!!但是,我们总不能说他们也是NaN吧?总而言之,得出的结论是:isNaN检测NaN并不可靠!!!
幸运的是,有一种可靠的并且准确的方法可以检测NaN。我们都知道,只有NaN是自己不等自己的,那么,我们就以使用不等于号(!==)来判断一个数是否等于自身,从而,可以检测到NaN了,如下:
var a = NaN;
a !== a; // true
var b = "foo";
b !== b; // false
var c = undefined;
c !== c; // false
var d = {};
d !== d; // false
var e = { valueOf: "foo" };
e !== e; // false
我们也可以把这种模式定义成一个函数,如下:
function isReallyNaN(x) {
return x !== x;
}
二 引用类型转值类型:
对象是可以转换成原始值的,最常见的方法就是把它转换成字符串,如下:
"the Math object: " + Math; // "the Math object: [object Math]"
"the JSON object: " + JSON; // "the JSON object: [object JSON]"
对象转换成字符串是调用了他的toSting函数的,你可以手动的调用它来检测一下:
Math.toString(); // "[object Math]"
JSON.toString(); // "[object JSON]"
类似的,对象也是可以转换成数字的,它是通过valueOf函数的,当然,你也是可以自定义这个valueOf函数的,如下:
"J" + { toString: function() { return "S"; } }; // "JS"
2 * { valueOf: function() { return 3; } }; // 6
如果,一个对象同时存在valueOf方法和toString方法,那么,valueOf方法总是会被优先调用的,如下:
var obj = {
toString: function() {
return "[object MyObject]";
},
valueOf: function() {
return 17;
}
};
"object: " + obj; // "object: 17"
但是,多数情况下,这都不是我们想要的,一般的,尽可能使valueOf和toString表示的值相同(尽管类型可以不同)。
通常情况下我们认为,将一个对象转换为字符串要调用toString()方法,转换为数字要调用valueOf()方法,但是真正应用的时候并没有这么简单,看如下代码实例:
var obj = {
webName: "脚本之家",
url:"softwhy.com"
}
console.log(obj);
console.log(obj.toString());
从上面的代码可以看出,toString()方法并没有将对象转换为一个能够反映此对象的字符串。
var arr = [1, 2, 3];
console.log(arr);
console.log(arr.valueOf());
从上面的代码可以看出,valueOf()方法并没有将对象转换为能够反映此对象的一个数字。
var arr = [1, 2, 3];
console.log(arr);
console.log(arr.toString());
数组对象的toString()方法能够将数组转换为能够反映此数组对象的字符串。
总结如下:
(1)有些对象只是简单继承了toString()或者valueOf()方法,比如第一个例子。
(2)有些对象则不但是继承了两个方法,而且还进行了重写。
所以有些对象的方法能够达成转换成字符串或者数字的目标,有些则不能。
调用toString()或者valueOf()将对象转换成字符串或者数字的规则如下:
调用toString()时,如果对象具有这个方法,则调用此方法;如果此方法返回一个值类型数据,那么就返回这个值类型数据,然后再根据所处的上下文环境进行相关数据类型转换。如果没有toString(),或者此方法返回值并不是一个值类型数据,那么就会调用valueOf()(如果此方法存在的话),如果valueOf()返回一个值类型数据,那么再根据所处的上下文环境进行相关的数据类型转换。
进一步说明:
(1)上面介绍了通常默认情况下valueOf()和toString()方法的作用(将对象转换为数字或者字符串),但是需要注意的是,这并不是硬性规定,也就是说并不是valueOf()方法必须要返回数字或者toString()方法必须要转换为字符串,比如简单继承的这两个方法就无法进行实现转换为数字和字符串的功能,再比如,我们可以自己称谢这两个方法,返回值也没有必要是数字或者字符串。
(2)还有需要特别注意的一点就是,调用toString()方法可以转换为字符串,但不一定转换字符串就是首先调用toString()方法。
看如下代码实例:
var arr = [];
arr.valueOf = function () { return "1"; }
arr.toString = function () { return "2"; }
console.log(arr + "1"); //11
上面的代码中,arr是要被转换为字符串的,但是很明显是调用的valueOf()方法,而没有调用toString()方法。有些朋友可能会有这样的质疑,难道[2]这样的数字转换成字符串”2”,不是调用的toString()方法吗。
代码如下:
var arr = [2];
console.log(arr + "1");//21
其实过程是这样的,首先arr会首先调用valueOf()方法,但是数字的此方法是简单继承而来,并没有重写(当然这个重写不是我们实现),返回值是数组对象本身,并不是一个值类型,所以就转而调用toString()方法,于是就实现了转换为字符串的目的。
总结如下:
大多数对象隐式转换为值类型都是首先尝试调用valueOf()方法。但是Date对象是个例外,此对象的valueOf()和toString()方法都经过精心重写,默认是调用toString()方法,比如使用+运算符,如果在其他算数运算环境中,则会转而调用valueOf()方法。
代码实例如下:
var date = new Date();
console.log(date);
console.log(date + "1");
console.log(date + 1);
console.log(date - 1);
console.log(date * 1);