如果你只想知道不同情况下使用何种方式来进行类型转换,请直接看总结。如果你还想进一步的了解不同方式的特点,请直接看转换到具体类型每一节的小结。当然我更希望您能耐心看完全文。
javascript数据类型可以相互转换,既可以调用相应的javascript函数来显式类型转换,javascript引擎也能够自动的进行隐式类型转换。我们来看一个示例:
var age = 30;
age.toString() + 'year old'; // '30 year old'
age + ' years old'; // '30 years old'
在运行age.toString() + 'year old'
时,age变量通过调用toString函数显式的从Number型转换成String型。而在运行age + ' years old'
时,我们没有显式的调用函数,age也被转换成String型,这里就是javascript引擎做了隐式类型转换。隐式类型转换可以认为javascript引擎调用的相应的类型转换函数来进行类型转换,age + ' years old'
其实等价于age.toString() + 'years old'
,隐式类型转换和显式类型转换其实是一回事情。
本文详细说明javascript各种类型之间如何进行类型转换,我们会介绍一些通用的转换方式,然后介绍具体转换到某种类型的方法。
javascript的对象都继承两个用于类型转换的方法toString和valueOf。
valueOf方法将对象类型转换成原始值,如果没有被重写,valueof默认(Object.prototype.valueOf
)返回对象本身。Number/String/Boolean对象重写了valueOf方法,在Chrome DevTools可以看到它们对应的原始值,如下图:
其他绝大部分对象类型都没有重写valueof。toString方法将对象转换成String型,如果没有被重写,toString方法默认(Object.prototype.toString
)返回"[object type]"(type是数据类型)。Number/String/Boolean对象重写了toString方法。
本节示例如下:
var obj = {name: 'jerry'};
// valueOf 默认返回对象本身
obj.valueOf() === obj; // true
// String对象重写了valueOf
new String('jerry').valueOf(); // 'jerry'
// toString 默认返回 "[object type]"
obj.toString(); // "[object Obejct]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
function A(){};
new A().toString(); // "[object Object]"
// Boolean类型重写了toString。(注意:调用之前true被包装成对象)
true.toString(); // "true"
toString和valueOf一般不会直接被调用,多用于隐式类型转换,我们不需要进一步详述。
题外话:def.js中非常有趣的利用了valueOf方法,有兴趣的同学可以看下(重写valueOf方法,利用执行<<时隐式调用valueOf来实现ruby-style的继承)。
用函数的方式调用对象的构造函数其实是做类型转换, 如:String(a)
是把a转换成String型,而new String(a)
是用a来构造一个String对象。我们一下子有了一大票类型转换函数,转换成String型的String(obj)
方法, 转换成Number型的Number(obj)
, 转换成Boolean型的Boolean(obj)
方法等等。
本节示例如下:
// 函数式调用构造函数其实在做类型的转换
String(30); // "30"
Number('123'); // 123
Boolean(0); // false
// 函数式调用 vs new
typeof String(30); // "string"
typeof new String(30); // "object"
对于String/Number/Boolean等函数针对不同类型的参数转换得到怎样的结果,会在下一章转换到具体类型中详细说明。
我们在对象类型转换成原始类型节,已经说明对象的toString方法可以将对象转换成String型,Number/Boolean型可以自动包装成对象然后调用toString方法,但是Null/Undefined类型无法调用toString方法。
Number对象的toString方法可以接受一个进制参数,指定数字以何种进制(2进制/8进制/16进制...)的表示。
本节示例如下:
// Number/Boolean型自动包装成对象然后调用toString方法
(123).toString(); // "123"
true.toString(); // "true"
({name: 'jerry'}).toString(); // "[object Object]"
// toString(radix) - 数字指定进制的字符串表示
(123).toString(2); // "1111011"
(123).toString(16); // "7b"
// null/undefined无法调用toString方法
null.toString(); // TypeError: Cannot read property 'toString' of null
undefined.toString(); // TypeError: Cannot read property 'toString' of undefined
我们在函数式调用构造函数节,已经说明用函数的方式调用String构造函数,可以将其他类型转换成String型。因为待转换的数据是通过参数传入的,因而能够处理Null/Undefined类型。关于不同类型转换成String型的结果,详情请参见es规范9.8节。
本节示例如下:
String(123); // "123"
String(true); // "true"
String({name: 'jerry'}); // "[object Object]"
String(null); // "null"
String(undefined); // "undefined"
"" + obj
利用隐式类型转换将obj转换成String型。当obj和""做+操作时,左操作数("")是String型,右操作数需要也是String型,如果obj不是String型,obj会被隐式类型转换为String型。隐式类型转换其实和调用String(obj)效果相同。
本节示例如下:
"" + 123; // "123"
"" + true; // "true"
"" + {name: 'jerry'}; // "[object Object]"
"" + null; // "null"
"" + undefined; // "undefined"
数值对象有一些方法,用于将数据类型转换成指定格式的字符串。Number.prototype.toPrecision指定数字精度, Number.prototype.toFixed指定小数点后的位数,Number.prototype.toExponential指定以指数形式表示数字。
本节示例如下:
// toPrecision指定数字的数量,会进行四舍五入,不够补零
(5.125).toPrecision(3); // "5.13"
(25).toPrecision(5); // "25.000"
// toFixed指定小数的数量,会进行四舍五入,不够补零
(3.2287).toFixed(3); // "3.229"
(25).toFixed(5); // "25.00000"
// toExponential指定为指数形式表示数字,并能指定小数点后位数
778.1234.toExponential(2); // "7.78e+2"
2.1节小结:
推荐使用"" + obj的方式来将其他类型转换成String类型。如果将Number型转换成指定格式的字符串可以使用obj.toString(radix)的方式或numObj.toPrecision/toFixed/toExponential。
我们在函数式调用构造函数节,已经说明用函数的方式调用Number构造函数,可以将其他类型转换成Number型。关于不同类型转换成Number型的结果,详情请参见es规范9.3节。本节示例如下:
// String to Number
Number("123.4"); // 123.4
Number(""); // 0
// Boolean to Number
Number(true); // 1
Number(false); // 0
// Object to Number
Number({}); // NaN
// Null to Number
Number(null); // 0
// Undefined to Number
Number(undefined); // NaN
一元操作符+把它的操作数转换成Number类型。+obj
其实和调用Number(obj)效果相同。 本节示例如下:
// String to Number
+"123.4"; // 123.4
+"123.4a"; // NaN
+""; // 0
// Boolean to Number
+true; // 1
+false; // 0
// Object to Number
+{}; // NaN
// Null to Number
+null; // 0
// Undefined to Number
+undefined; // NaN
parseInt/parseFloat专门用于将String类型转换成Number类型。在Number(obj)节,我们知道Number("")
值为0,而parseInt("")
值为NaN,更加合理,更加符合直觉。parseInt/parseFloat是按照字符顺序一个个parse的,因此能够正确处理"123.4a"这样的String, 在Number(obj)我们知道Number("123.4a")
值为NaN,而parseFloat("123.4a")
值为123.4。parseInt/parseFloat接受的是String类型参数,如果参数是Boolean/Null/Undefined/Object类型,会被隐式转换成String型后,再逐字符parse,结果自然为NaN。parseInt还有第二个参数radix,用来指定进制(2/8/16/...进制),详情请见mdn parseInt。 本节示例如下:
// parse String类型
parseFloat("123.4"); // 123.4
parseFloat("123.4a"); // 123.4
parseInt(""); // NaN
parseInt("110", 2); // 6
// parse非String类型,会先隐式转换成String型,再parse
parseInt(true); // NaN
parseInt({}); // NaN
parseInt(null); // NaN
parseInt(undefined); // NaN
2.2节小结:
如果要把String转换成Number型,推荐使用parseInt/parseFloat。如果要把未知类型转换成Number型,推荐使用+obj。
我们在函数式调用构造函数节,已经说明用函数的方式调用Boolean构造函数,可以将其他类型转换成Number型。关于不同类型转换成Boolean型的结果,详情请参见es规范9.2节。本节示例如下:
// String转换成boolean, 空字符串为false, 其他为true
Boolean(""); // false
Boolean("jerry"); // true
// Number转换成Boolean, 0/NaN为false,其他都为true
Boolean(0); // false
Boolean(NaN); // false
Boolean(123); // true
// Object转换成Boolean,都为true
Boolean({}); // true
// Null to Boolean
Boolean(null); // false
// Undefined to Boolean
Boolean(undefined); // false
逻辑非操作符!先将操作数obj转换成Boolean型,如果转换的结果为true,则返回false,否则返回true,详情请参见es规范11.4.9节。显然,如果对操作数obj执行逻辑非操作符!的结果再执行逻辑非操作符!操作,就是将obj转换成了Boolean型。!!obj
其实和调用Boolean(obj)效果相同。本节示例如下:
// String转换成boolean, 空字符串为false, 其他为true
!!""; // false
!!"jerry"; // true
// Number转换成Boolean, 0/NaN为false,其他都为true
!!0; // false
!!NaN; // false
!!123; // true
// Object转换成Boolean,都为true
!!{}; // true
// Null to Boolean
!!null; // false
// Undefined to Boolean
!!undefined; // false
2.3节小结:
推荐使用!!obj的方式来将其他类型转换成Boolean类型。
当javascript引擎试图去操作错误的数据类型时,引擎自动会其转换成正确的数据类型,这个过程就是隐式类型转换。我们也可以通过函数调用或其他操作符进行显示类型转换。
其他类型转换成String类型,推荐使用"" + obj。其他类型转换成Number类型推荐使用+obj,如果是将String型转换成Number型推荐使用parseInt/parseFloat。其他类型转换成Boolean类型推荐使用!!obj。
进一步了解Javascript类型系统:
本文来自网易实践者社区,经作者魏文庆授权发布。