JavaScript类型转换机制及各类型检查方法
在JavaScript中,我们通常会碰到有关于值比较的问题。由于JavaScript类型转换机制的存在,往往会遇到一些尴尬的问题。比如我们会遇到这样的问题 alert(true == 1); // 结果返回true 以及 alert([] == 0); // 结果依旧返回true 等等问题。在介绍JavaScript类型转换机制之前,首先我们必须了解一下JavaScript的原始值及引用对象。
1 JavaScript的原始值及引用对象
JavaScript的值分为两种类型:原始类型和引用类型(也称做对象)。
原始类型包括:字符串、数字、布尔值、null和undefined
引用类型包括:数组和函数
1.1 原始类型与引用类型的区别
1、原始类型的值是不可变的,引用类型的值是可变的。
var str1 = "hello"; // 首先存在一个为"hello"的字符串,我们使用变量str1接收
var str2 = str1; // 然后我们将str1赋值给str2
str1 = str1.toUpperCase(); // 接着我们调用一下字符串的方法,将字符串中的字母全部大写
alert(str2); // 最后我们输出一下str2 结果依旧是 hello
当然举这样一个例子,事实上是说明,字符串中所有的方法看上去返回一个修改后的字符串,实际上返回的是一个新的字符串。对于数字和布尔值就更加明显了--改变数字的值本身就说不通。
2、原始类型的比较,只有它们的值相等的时候它们才相等。对于字符串来说就不太好理解。
JavaScript规定字符串,当前仅当它们的长度相等及每个索引的字符都相等时,JavaScript才认为他们相等。而引用类型的比较:当且仅当它们引用同一个对象时,它们才相等。那么,即使两个对象包含同样的属性及相同的值,它们也不一定是相等的。
var a = {x:1};
var b = {x:1};
alert("比较1:" + (a === b)); // 结果返回false
var a = [];
var b = [];
alert("比较2:" + (a === b)); // 结果返回false
var a = [];
var b = a;
var c = b;
alert("比较3:" + (a === b)); // 结果返回true
2 JavaScript类型转换机制
了解了JavaScript的值的类型之后,我们再来看JavaScript类型转换机制。JavaScript会根据需要自行转换类型。这一点我们从以下示例就可以看出。
var str = "30";
str = str * 10; // 因为执行乘法运算,乘法的两边都应该是数字类型,JavaScript会根据需要将str转换为数字类型
alert(str); // 结果返回300
var str2 = 30;
str2 = str2 + "10"; // 因为执行+运算,因为+的一遍包含字符串"10",因此我们可以将+看出连接符,JavaScript会根据需要将str转换为字符串
alert(str2); // 结果返回3010
![](https://i-blog.csdnimg.cn/blog_migrate/e9de0f93fc1338886cf2e1e027ed4b71.gif)
2.1 JavaScript各类型之间的转换对应表
根据《JavaScript权威指南》,以下表格说明了各类型之间的转换。空单元格表示不必要也没有执行转换。
值 | 转换为 | |||
字符串 | 数字 | 布尔值 | 对象 | |
undefined | "undefined" | NaN | false | throws TypeError |
null | "null" | 0 | false | throws TypeError |
true | "true" | 1 | new Boolean(true) | |
false | "false" | 0 | new Boolean(false) | |
""(空字符串) | 0 | false | new String("") | |
"1.2"(非空,数字) | 1.2 | true | new String("1.2") | |
"one"(非空,非数字) | NaN | true | new String("one") | |
0 | "0" | false | new Number(0) | |
-0 | "0" | false | new Number(-0) | |
NaN | "NaN" | false | new Number(NaN) | |
Infinity | "Infinity" | true | new Number(Infinity) | |
-Infinity | "-Infinity" | true | new Number(-Infinity) | |
1(无穷大,非0) | "1" | true | new Number(1) | |
{}(任意对象) | 具体见下文 | 具体见下文 | true | |
[](任意数组) | "" | 0 | true | |
[9](一个数字元素的数组) | "9" | 9 | true | |
['a'](其他数组) | 使用join()方法 | NaN | true | |
function(){}(任意函数) | 具体见下文 | NaN | true |
说明:
(1)原始值到对象的转换非常简单。原始值通调用String(),Number(),或Boolean()构造函数,转换成为它们各自的包装对象。
(2)null和undefined属于例外,当它们用在期望是一个对象的地方时,都会造成一个类型错误(TypeError)异常,而不会执行正常的转换
(3)对象到原始值的转换比较复杂。具体请看后续分析。
2.2 显示类型转换
通过调用Boolean()、Number()、String()或Object()函数显示的将数据转换为期望的类型的方法。
Number("1") ==> 1
String("true") ==> "true"
Boolean([]) ==> true
Object("3") ==> new Number("3")
需要注意的是:如果试图将null或undefined转换成为对象,则会报类型错误(TypeError)具体如上表所示。 如果是Object()函数,则会返回一个新创建的空对象
2.3 隐式类型转换
JavaScript中的某些运算符会做隐式转换, 例如var x = "30"; +x; ==> 等价于 x-0。像这种通过JavaScript中的某些运算符达到数据类型转换目的的方法称之为隐式转换。
x + ""; // 等价于String(x);
+x; // 等价于Number(x);或 x - 0;
!!x; // 等价于Boolean(x);需要注意的是双感叹号
2.4 对象转换为字符串
1、 如果对象具有toString()方法,则调用这个方法,如果它的返回值是一个原始值,JavaScript将这个值转换为字符串(如果其本身不是字符串),并返回这个字符串结果。详细的转换对比上表。
(1)数组转换为字符串
数组转换为字符串时,调用toString()方法,该方法将数组转换成一个字符串,并在元素间添加逗号后结合成结果字符串,例如:["1","2","3"].toString(); // ==> 1,2,3
var a = ["1","2","3"];
var b = "1,2,3";
alert(a == b);
(2)函数类转化为字符串
函数类转换为字符串时,通常toString()方法实际返回的是这个函数的实现定义表现方式。Eg:(function(x){f(x);}).toString; ==> // function(x){f(x);}
var a = "function(x){f(x);}";
var b = function(x){f(x);};
var c = function(x){
f(x);
};
console.log("a == b:" + (a == b));
console.log("a == c:" + (a == c));
console.log(c.toString());
2 、 如果对象没有toString()方法,或者这个方法不返回一个原始值,那么JavaScript会调用valueOf()方法。如果这个方法存在JavaScript则会调用它。如果返回值是原始值,JavaScript会将这个值转换为字符串(如果其本身不是字符串的话),并返回这个字符串结果。
var obj = {
name:"",
age:12,
valueOf:function(){
return "this is valueOf()"
}
};
alert("查看调用的方法:" + obj);
备注:根据《JavaScript权威指南》说明,理论上应该先调用toString(),如果没有则调用valueOf()方法,而事实上则先调用valueOf()方法,然这一点我很费解。知道原因的朋友,麻烦留言一下。具体如下:
var obj = {
name:"",
age:12,
toString:function(){
return "this is toString()"
},
valueOf:function(){
return "this is valueOf()"
}
};
alert("查看调用的方法:" + obj);
3、否则, 无法从toString()或valueOf()获得一个原始值。因此这时将抛出一个类型错误异常。
var obj = {
name:"",
age:12,
toString:function(){
return new Object();
},
valueOf:function(){
return new Object();
}
};
alert("查看调用的方法:" + obj);
2.5 对象转换为数字
对象转换为数字的过程与到字符串类似,只是它会首先尝试使用valueOf()方法。
1、如果对象具有valueOf()方法,则调用这个方法,如果它的返回值是一个原始值,JavaScript将这个值转换为数字(如果其本身不是数字),并返回这个数字。详细的转换对比上表。
2 、 如果对象没有valueOf()方法,或者这个方法不返回一个原始值,那么JavaScript会调用toString()方法。如果这个方法存在JavaScript则会调用它。如果返回值是原始值,JavaScript会将这个值转换为数字(如果其本身不是数字的话),并返回这个数字。
3、否则, 无法从toString()或valueOf()获得一个原始值。因此这时将抛出一个类型错误异常。
3 “==”与“===”
在讲述各类型比较之前,我们先了解一下“==”(相等运算符)与“===”(恒等运算符)
3.1 “===”
严格相等运算符“===”,也称做恒等运算符,它用来检测两个操作数是否严格相等。
恒等运算符“===”,首先比较两个操作数数据类型是否相同,然后比较这两个值,比较过程中没有任何类型转换:
(1) 如果两个值类型不同,则它们不同。
(2)如果两个值都是null或者都是undefined,则他们相等。
(3)如果两个值都是布尔值true或者都是false,则他们相等。
(4)如果其中一个值是NaN,或者两个值都是NaN,则他们不相等。NaN和其他任何值都不相等,包含它本身。通过x!==x判断x是否为NaN,只有当x为NaN时,这个表达式才为true。
(5)如果两个值都为数字且数值相等,则它们相等。如果一个值是0,另一个值是-0,它们同样相等。
(6)如果两个值为字符串,且所含对应为上的16位 数完全相等,则他们相等。如果他们的长度或内容不同,则它们不相等。两个字符串可能完全意义上一样且显示出的字符也一样,但是具有不同编码的16位值,则他们不等。
(7)如果两个引用值指向同一个对象、数组、函数,则他们相等。如果指向不同的对象,则他们不等,尽管两个对象具有完全一样的属性。
3.2 “==”
相等运算符“==”,用来检测两个操作数是否相等,不同意恒等运算符“===”的是,相等运算符“==”,只比较两个操作数的值是否相等,如果两个操作数的数据类型不同,那么相等运算符“==”会尝试做做隐式类型转换,然后进行比较。
(1)如果两个数据类型相同,则和恒等运算符所述规则一样。如果严格相等,那么比较结果相等,如果不严格相等,则比较结果为不相等。
(2)如果两个操作数的数据类型不同,相等运算符“==”也可能认为他们相等。检查相等会遵循如下规则和类型转换:
①如果一个值是null,另一个是undefined,则他们相等。
②如果一个值是数字,另一个值是字符串,则先将字符串转换为数字,然后使用转换后的值进行比较
③如果其中一个值是true,则将其转换成1再进行比较。如果其中一个值是false,则将其转换成0再进行比较。
④如果一个值是对象,另一个值是数字或字符串,则现将对象转换成原始值(转换规则如上述),然后进行比较。
⑤其他不同类型之间的比较不相等。
3.3 总结
恒等运算符“===”
数据类型相同时:
原始值直接比较值,值相等则他们相等,需要注意的是String类型必须具有相同编码的16位值。
引用类型,需要注意是否指向同一个对象、数组、函数。Eg: var a = [1,2,3];var b = [1,2,3]; a === b; 结果为false。
var a = [1,2,3];
var b = [1,2,3];
alert("a === b:" + (a === b));
数据类型不同时:直接返回false;
相等运算符“==”
数据类型相同时,比较结果与恒等运算符比较结果相同。
数据类型不同时:
(1)null与undefined除与自己相等外,他们彼此也相等,即 null == undefined,结果返回为true。
(2)如果都是原始值,会将其他类型转换为数字,然后进行比较。
(3)如果其中一个类型是对象,则将对象转换为原始值,然后在进行比较。
....未完