在 JavaScript 中,值可以有不同的类型。通过显式的_类型转换_可以改变变量的类型。 除此之外,当上下文需要时,JavaScript 还会执行_类型强制转换_(隐式类型转换)。
JavaScript 不像许多其他语言那样有强制转换为(另一种)类型的语法结构,但可以使用一些内置的辅助方法。
最值得注意的是,全局对象 Boolean、Number 和 String 可以当作函数使用,把值转换成对应的类型。
用 Boolean(value) 可以把任何值转换为布尔值。
这是怎么做到的?
有一组固定的值,称为_假值_,它们会被转换为 false。
最重要的是,false、0、空字符串、null、undefined 和 NaN 都是假值。
MDN 上关于 “Falsy” 的文章列出了完整的清单。
对于所有其他值,Boolean 返回 true。
这些值称为_真值_。
Boolean(-1);
// => true
Boolean(0);
// => false
Boolean(' ');
// => true
Boolean('');
// => false
注意,根据上述规则,在 JavaScript 中 '0'、'false'、[] 和 {} 都是真值。
Number(value) 可以用来把值转换为数字。
字符串开头和结尾的空白符会被忽略,空字符串会被转换为 0。
如果你尝试转换非原始值,或者一个不表示数字的字符串,不会抛出错误。
结果会是 NaN(Not-A-Number)。
Number(' -12.34 ');
// => -12.34
Number('1,2');
// => NaN
Number('1 2');
// => NaN
Number('');
// => 0
Number('10e3');
// => 10000
Number({ key: '123' });
// => NaN
下面是 Number 对其他原始值返回的结果。
Number(true);
// => 1
Number(false);
// => 0
Number(null);
// => 0
Number(undefined);
// => NaN
注意,与上一个例子不同,不带任何实参调用 Number() 被定义为返回 0。
JavaScript 还提供了 parseInt 和 parseFloat 两个函数。
它们对于哪些字符串可以转换为数字的规则更宽松。
因此,最好优先使用 Number 作为转换函数,以避免意外结果。
parseInt('123a45');
// => 123
Number('123a45');
// => NaN
用 String(value) 可以把值转换为字符串。
对于原始值,结果和你预期的一样。
String(12.34);
// => '12.34'
String(false);
// => 'false'
String(null);
// => 'null'
String(undefined);
// => 'undefined'
对于数组,String 函数会为每个元素应用字符串转换,并用逗号把结果连接起来。
你也可以自己调用 join 方法,比如自定义分隔符。
不过,在这些情况下,null 和 undefined 会被转换为空字符串。
String([42, null, true, 'abc']);
// => '42,,true,abc'
对于对象,默认情况下 String 会返回一段没什么用的文本。
String({ key: 'value' });
// => '[object Object]'
你可以自定义转换行为,比如提供一个 toString 方法。
javascript.info 上的“对象到原始值的转换”一节解释了细节。
为对象和数组获得更好的字符串表示的另一种常见方法是使用 JSON 编码。
你可以用 JSON.stringify 把它转换成字符串,再用 JSON.parse 转回对象或数组。
const obj = {
name: 'Gilda Guerra',
address: {
city: 'Goiânia',
},
};
JSON.stringify(obj);
// => '{"name":"Gilda Guerra","address":{"city":"Goiânia"}}'
在某些上下文中,JavaScript 会在求值某条语句之前自动把值转换为另一种数据类型。 这种隐式转换称为_类型强制转换_。
当值用在布尔上下文中时,JavaScript 会应用与 Boolean 函数相同的规则来隐式转换该值。
当 if 语句的条件不是布尔值时,会应用强制转换来判断条件是否成立。
同样适用于三元运算符 ? 的第一个操作数。
const num = 0;
if (num) {
// this block is NOT executed because 0 is falsy
}
const name = 'Jin';
name ? 'name was provided' : 'no name provided';
// => 'name was provided'
逻辑非运算符 ! 的操作数在应用非运算之前也会被强制转换为布尔值。
const name = '';
!name;
// => true
上述行为的一个结果是,!!value 与 Boolean(value) 的效果相同。
尽管如此,为了提高可读性,你应该使用 Boolean。
JavaScript 也会对逻辑与(&&)和逻辑或(||)运算符的操作数应用强制转换。
但请记住,表达式的结果不一定是布尔值。
它会返回其中一个原始操作数(参见 MDN 上的逻辑运算符)。
null || 'hello';
// => 'hello'
如果加法运算符 + 用于原始值,并且其中一个操作数是字符串,那么另一个操作数也会被强制转换为字符串。
转换逻辑与使用 String 函数时相同。
之后,两个字符串会被拼接起来。
let name;
'hello ' + name;
// => 'hello undefined'
对于嵌入模板字符串中的非字符串值,也会发生同样的隐式转换。
const degrees = 23;
`It is ${degrees} °C`;
// => 'Is is 23 °C.';
许多运算符会按照上面解释的 Number 函数的逻辑,把操作数强制转换为数字(如有必要)。
+(如果不涉及字符串)、-、*、/、%、**
+、-
>、>=、<、<=
|、&、^、~
关于这些运算符的更多细节,请参阅 MDN 的运算符列表。
当操作数可能是字符串时,最好始终用 Number 函数显式转换,以免出错。
'1' + '2';
// => '12'
// addition operator in string context as explained above
Number('1') + Number('2');
// => 3
有时你会看到用一元加号运算符把字符串强制转换为数字。
不推荐这样做,因为它比显式调用 Number 难读得多。
const value = '42';
+value;
// => 42
Number(value);
// => 42
使用宽松相等和不相等运算符 ==/!= 时,也常常涉及隐式转换为数字。
不过,这些运算符的确切逻辑相当复杂(参见 MDN 上的宽松相等)。
结果难以预测,有时并不符合你的预期。
请改用严格相等/不相等运算符 ===/!==,以避免这些隐式转换。