javascript 类型转换
JavaScript任何时候都可以为变量赋值(数字、字符串等),不过如果我让两个变量相加,其中一个是数字,另一个是字符串,会发生什么呢?
JavaScript很聪明,它会尝试根据你的需要转换类型。例如,如果你将一个字符串和一个数字相加,它就会把这个数字转换为一个字符串,然后将两个字符串串联起来。这就是这篇文章要讲的JavaScript类型转换,
介绍:
JavaScript中变量可以分配到Reference value或者Primitive Value。Reference value也称为对象,存储在堆中,Reference value的变量指向对象在内存中的地址。Primitive Value包含Undefined、Null、Boolean、Number、String。Reference Value包括function、array、regex、date等。
我们可以使用typeof来确定JavaScript变量的数据类型。
typeof null; // "object" typeof undefined; // "undefined" typeof 0; // "number" typeof NaN; // "number" typeof true; // "boolean" typeof "foo"; //"string" typeof {}; // "object" typeof function (){}; // "function" typeof []; "object"
1. 转换成Boolean
使用Boolean()函数,可以将任意类型的变量强制转换成布尔值。还有当JavaScript遇到预期为布尔值的地方(比如if语句的条件部分,a ==(>或者<) b的比较运算,a &&b(a||b或!a)的逻辑运算),就会将非布尔值的参数自动转换为布尔值。
Primitive Value除了undefined
、null
、""(空字符串)
、0
、-0
、NaN
转换为false,其他的均转换为true。
值 | undefined | null | true | false | ""(空字符串) | "1.2" | "one" | 0 | -0 | NaN | Infinity | -Infinity | 1(其他非无穷大的数字) | {} | [] | [9] | ['a'] | function(){} |
布尔值 | false | false | true | true | false | true | true | false | false | false | true | true | true | true | true | true |
true | true |
Boolean(undefined); //false Boolean(null); //false Boolean(""); //false Boolean("1.2") //true Boolean(0) //false Boolean(-0) //false Boolean(NaN) //false Boolean(Infinity) //true Boolean(-Infinity) //true Boolean(1) //true Boolean({}) //true Boolean([]) //true Boolean([9]) //true Boolean('a') //true Boolean(function(){}) //true
任何Reference value(对象)的布尔值都是true。甚至值为false、undefined或者null的Boolean对象,其值都为true。
Boolean(new Boolean(undefined)) //true Boolean(new Boolean(null)) //true Boolean(new Boolean(false)) //true
在条件语句中,这些Boolean对象都将作为true来判断。例如,下面的条件语句中,if就将对象x看作是true:
var x = new Boolean(false); if(x){ // ...这里的代码仍会被执行 }
2. 转换成Number
数值转换主要发生在以下三种情况:
1. 使用Number()函数强制转换。
2. 需要数字的函数中。
比如:Math.sin(val), isNaN(val), val+1, val-1, val/1等四则运算中,还包括+val, -val等运算中。
3. 比较运算中。
比如:'00100' > 1 //false,而 '00100' > '1' //true
使用Number()函数
值 | undefined | null | true | false | ""(空字符串) | "1.2" | "123e-2" | "010" | "0x10" | "0xff" | "-010" | "-0x10" | "one" | 0 | -0 | NaN | Infinity | -Infinity | 1(其他非无穷大的数字) | {} | [] | [9] | ['a'] | function(){} | |
数字 | NaN | 0 | 1 | 0 | 0 | 1.2 | 1.23 | 10 | 16 | 255 | -10 | NaN | NaN | 0 | -0 | NaN | Infinity | -Infinity | 1 | 待讨论 | 0 | 9 | NaN | NaN |
Primitive Value转换成数值具有以下规则:
1. 数值: 转换后还是原来的值。
2. 字符串:如果可以被解析为数值,则转换为相应的数值,否则得到NaN。空字符串转为0.
3. 布尔值:true转成1,false转成0.
4. undefined: 转成NaN。
5. null: 转成0.
6. Number函数会自动过滤一个字符串前导和后缀的空格
[0] == 0 //true "\n0\n" == 0 //true "\n0\n" == false //true
Object转换成数值相对比较复杂些,Object转换成数值的算法如下:
1. 先调用对象自身的valueOf方法,如果该方法返回原始类型的值(数值、字符串和布尔值),则直接对该值使用Number方法,不在进行后续步骤。
2. 否则,如果valueOf返回符合类型的值,再调用对象自身的toString方法,如果toString方法返回原始类型的值,则对该值使用Number方法,不再进行后续步骤。
3. 否则,如果toString方法返回的是复合类型的值,则报错。
example:
1. 自定义valueOf。
var stu = { age: 18, valueOf: function(){ return this.age } }; console.log(+stu) //18
2. 如果与自定义toString,但是没有valueOf,解析器会使用toString来数值转换:
var stu = { age: 18, toString: function(){ return this.age } }; console.log(+stu) //18
3. 如果valueOf和toString返回的均不是原始值,则报错。
var stu = { age: 18, valueOf: function(){ return {} }, toString: function(){ return {} } } console.log(+stu) //Error: Uncaught TypeError: Cannot convert object to primitive value
3. 转换成String
字符串转换主要发生在以下两种情况:
1. 使用String()函数强制转换。
2. 当JavaScript遇到预期为字符串的地方,就会将非字符串的数据自动转为字符串。
比如:obj + 'string', '0'+0。
使用string()函数:
值 | undefined | null | true | false | ""(空字符串) | "1.2" | "one" | 0 | -0 | NaN | Infinity | -Infinity | 1(其他非无穷大的数字) | {} | [] | [9] | ['a'] | function(){} | |
数字 | "undefined" | "null" | "true" | "false" | "" | "1.2" | "one" | "0" | "0" | "NaN" | "Infinity" | "-Infinity" | "1" | 待讨论 | "" | "9" | 使用join()翻番连接各个元素,分隔符为逗号 | 待讨论 |
对象类型转换字符串类型步骤如下:
- 如果对象有toString方法,就调用toString方法,如果返回的是一个原始类型,把这个原始类型转换成字符串(当然如果toString返回的就是字符串就不需要了)
- 如果对象没有toString方法,或者toString返回的不是原始类型,就尝试调用valueOf方法,如果valueOf方法返回的是原始类型,则将原始类型转换成字符串(如果valueOf放回的就是字符串就不需要了)
- 如果toString方法和valueOf方法都不存在,或者他们的返回类型都不是原始类型,则抛出TypeError异常
example:
1. 自定义toString。
var stu = { toString: function(){ return "beauty" } }; String(stu) //beauty
2.自定义valueOf
var stu = { valueOf: function(){ return "student" } }; String(stu) //"[object Object]"
3. 自定义toString和valueOf
var stu = {
valueOf: function(){
return "student"
},
toString: function(){ return "beauty" } }; console.log(String(stu)) //“beauty”
4. toString和valueOf均不是原始值,则报错
var stu = { valueOf: function(){ return {}; }, toString: function(){ return {} } }; console.log(String(stu)) //Uncaught TypeError: Cannot convert object to primitive value
特例情况:+operator
先看下面的例子:
var stu = { toString: function(){ return "student"; }, valueOf: function(){ return 18; } }; stu + "foo" //"18foo"
[stu, "foo"].join(""); //studentfoo
在这个例子中,我们使用+操作符来座字符串连接,但是stu没有使用toString转换成"student",而是使用valueOf转换成数字18.然后与"foo"连接成"18foo"。结果不是我们预期的,但是它是怎么实现的?我们再看下一个例子。
var date1 = new Date(); date1.toString=function(){return "now";}; date1.valueOf=function(){return "wait";}; date1+"foo" //"nowfoo" [date1+"foo"].join(""); //"nowfoo"
在这个例子中,我们使用+操作符来作字符串连接,使用toString(),得到字符串"now".然后与"foo"连接成"nowfoo"。结果是我们预期的。
对于非日期型的对象,转换过程是先使用对象的valueOf()方法,如果返回的不是原始值或者valueOf不存在,那就会再调用toString()方法,如果返回的仍然不是原始值,那就会抛出类型错误的异常。而对于日期型的对象,它首先会使用toString()然后才是valueOf()。
参考文章:
阮一峰:数据类型转换
MDN: Boolean