1. 什么是类型转换?
Javascript 是一种弱类型语言,这意味着变量是没有明确类型的,而是由 JavaScript 引擎在编译时隐式完成。类型转换是将一种数据类型转换为另一种数据类型,例如:
20 + "twenty" // => "20twenty" "10" * "10" // => 100 2 - "x"
Javascript 使用严格相等(===)和宽松相等(==)来测试两个值的相等性,类型转换仅在使用宽松相等运算符时发生。当使用 === 测试严格相等时,要比较的变量的类型和值都必须相同,例如:
10 === 10 // true NaN === NaN // false
在上面的代码中,10和10都是数字并且是完全相等的,所以正如预期的那样返回了true
,两个 NaN 永远不会相等。当使用 == 测试宽松相等时,可能会发生隐式转换:
'20' == 20 // true false == 0 // true
对于任何数据类型,无论是原始类型还是对象,都可以进行类型转换。尽管原始类型和对象的转换逻辑各不相同,但是都只能转换为三种类型:字符串(string)、数字(number)、布尔值(boolean)。
JavaScript 中的类型转换有两种方式:
- 隐式类型转换: 由 JavaScript 编译器完成的自动类型转换。
- 显式类型转换: 由开发人员完成的手动类型转换。
下面先来看看 JavaScript 中的显式和隐式类型转换。
(1)显示类型转换
我们可以通过 JavaScript 内置的一些 API 将一种类型转换为另一种类型,这称为显式类型转化。执行显式类型转换的最简单方法是使用 Boolean()
、Number()
和 String()
、parseInt()
等函数,例如:
String(2 - true); // '1' '56' === String(56); // true Number('2350e-2'); // '23.5' Number('23') + 7; // 30 Boolean(''); // false Boolean(2) === true; //true
(2)隐式类型转换
隐式类型转换是将一种数据类型转换为另一种数据类型(确保在相同数据类型之间完成操作)以使运算符或函数正常工作,这种转换是由 JavaScript 编译器自动完成的,隐式类型转换也称为类型强制。例如:
'25' + 15; // '2515' 23 * '2'; // 46 23 - true; // 22 true - null; // 1 false + undefined; // NaN const arr = []; if(arr) { console.log('Hello World') };
下面这些常见的操作会触发隐式地类型转换,编写代码时要格外注意:
- 运算相关的操作符:+、-、+=、++、* 、/、%、<<、& 等。
- 数据比较相关的操作符: >、<、== 、<=、>=、===。
- 逻辑判断相关的操作符: &&、!、||、三目运算符。
① + 运算符
/* 一个操作数 */ + x // 将x转化为数字, 如果不能转化为数组将输出NaN + "1234string" // NaN + 1 // 1 + '1' // 1 + true // 1 + undefined // NaN + null // 0 + new Date() // 1660493819396 /* 两个操作数 */ a + b // 1. 如果其中任何一个是对象,则先将其转换为原始类型 {} + {} // '[object Object][object Object]' [] + [] // '' [] + new Date() // 'Mon Aug 15 2022 00:18:18 GMT+0800 (中国标准时间)' // 2. 如果一个是字符串,则将另一个转换为字符串 1 + '' // '1' '' + 1 // '1' '' + true // 'true' // 3. 否则,将两者都转换为数字 1 + true // 2 true + true // 2
② -、*、/、++、--
// 将一个或多个值转换为数字 - '1' // -1 [] - 1 // -1 [] - {} // NaN
③ ==、!=
javascript 复制代码 // 两个操作数 a == b // 1. 如果一个是 `null` 而另一个是 `undefined`,它们是相等的 null == undefined // true // 2. 如果一个是数字,另一个是字符串,将字符串转换为数字,再比较 1 == '1' // true // 3. 如果其中一个是布尔值,将其转换为数字,再次比较 true == 1 // true false == 0 // true // 4. 如果一个是对象,另一个是数字或字符串,将对象转换为原始类型,再次比较 [1] == 1 // true ['1'] == '1' // true
下图是在使用 == 时,判断两个操作数是否相等的总结(绿色表示相等,白色表示不等):
④ >、>=、<、<=
javascript 复制代码 // 两个操作数 a > b // 1. 如果其中一个是对象,则将其转换为原始类型,再次比较 [2] > 1 // true // 2. 如果两者都是字符串,使用字母顺序比较它们 'b' > 'a' // true // 3. 如果其中一个是数字,则将一个或两个非数字转换为数字 '2' > 1 // true
⑤ in
/* 如果左操作数不是字符串,则将其转换为字符串 */ a in b '1' in {1: ''} // true 1 in {1: 'a'} // true 1 in ['a', 'b'] // true
2. 常见类型转换
(1)字符串转换
将数据类型转换为字符串称为字符串转换,可以使用 String()
函数将数据类型显式转换为字符串。当一个操作数是字符串时,可以通过使用 +
运算符来触发隐式字符串转换。
① 数字 => 字符串:
Number对象的 toString()
方法会返回指定 Number 对象的字符串表示形式。String()
和 new String()
会把对象的值转换为字符串。
String(20); // '20' String(10 + 40); // '50' (10 + 40).toString(); // '50' new String(10 + 20); // '30'
② 布尔值 => 字符串:
String()
和 toString()
方法会将布尔值转化为对应的字符串形式。
String(true); // 'true' String(false); // 'false' true.toString() // 'true' false.toString() // "false"
③ 数组 => 字符串:
String()
方法会将数组元素通过逗号连接起来,无论嵌套多少层,都会将其展开并返回元素拼接好的字符串。如果是空数字,会返回空字符串:
String(true); // 'true' String(false); // 'false' true.toString() // 'true' false.toString() // "false"
④ 对象 => 字符串:
使用 String() 方法会将对象转化为 '[object Object]'
,无论对象是否为空对象:
String({name: "Hello"}); // '[object Object]'
⑤ null / undefined / NaN => 字符串:
使用 String()
方法会将 null
、undefined
、NaN
转化为其对应的字符串形式:
String(undefined); // 'undefined'String(null); // 'null'String(NaN); // 'NaN'
⑥ 日期 => 字符串:
String(newDate('2022-08-20')) // 'Sat Aug 20 2022 08:00:00 GMT+0800 (中国标准时间)'
⑦ 隐式转换
当任何数据类型使用+
运算符与字符串连接时会发生到字符串的转换(隐式转换):
"25" + 56; // '2556' "25" + null; // '25null' "Hello " + undefined; // 'Hello undefined' "25" + false; // '25fasle' "25" + {}; // '25[object Object]' "25" + [10]; // '2510'
所以,当我们想要创建一个操作并且操作数类型之一是字符串时,应该小心使用类型强制转换。
⑧ 总结
下面是 ECMAScript 规范中将数据类型转换为字符串的规则:
ECMAScript 规范:262.ecma-international.org/5.1/#sec-9.…
(2)布尔转换
将数据类型转换为布尔值称为布尔转换。这种转换既可以由 Boolean()
函数显式完成,也可以在逻辑上下文中隐式完成(如if/else )或通过使用逻辑运算符( ||、&&、! )触发。
① 字符串 => 布尔值:
使用 Boolean()
方法转化字符串时,只有当字符串为空时会返回false
,其他情况都会返回 true
:
Boolean('hello'); // true Boolean(' '); // true Boolean(''); // false
② 数字 => 布尔值:
使用 Boolean()
方法转化数字时,只有 0、-0 或 NaN 会转化为 false
,其他情况会返回 true
:
Boolean(-123); // true Boolean(123); // true Boolean(0); // false Boolean(-0); // false Boolean(NaN); // false
③ 数组 / 对象 => 布尔值:
使用 Boolean()
方法转化数组或对象时,无论数组和对象是否有内容,都会返回true
:
Boolean([1, 2, 3]); // true Boolean([]); // true Boolean({}); // true Boolean({'hello': 'world'}); // true
④ null / undefined => 布尔值:
使用 Boolean()
方法转化null
或undefined
时,都始终返回 false
:
Boolean(undefined); // false Boolean(null); // false
⑤ 隐式转换
在数学运算中,true
转换为 1,false
转换为 0:
j
true + 5; // 6 false + 5; // 5 5 - true; // 5 5 - false; // 4
⑥ 逻辑运算符、逻辑上下文
// 如果其中一个不是布尔值,则将其转换为布尔值 Boolean( null || undefined || 0 || -0 || NaN || '' ) // false Boolean( 1 && 'a' && { } && [] && [0] && function(){} ) // true true && false // false true && true // true true || false // true true || !false // true
注意,逻辑运算符,例如 ||
或 &&
内部进行布尔转换,但实际上返回原始操作数的值,即使它们不是布尔值。
javascript
复制代码
'hello' && 123; // 123
可以使用双感叹号(!!
)来将变量转为为布尔值:
!!0 // false !!"" // false !!" " // true !!{} // true !![] // true !!true // true
if、else if、while、do/while 和 for 使用与 &&、||、! 相同的隐式类型转换方式(逻辑表达式)。
下面是在 if 语句(逻辑上下文)中的隐式转换规则(绿色为true
,白色为false
):
⑦ 总结
除了下面这些之外的所有其他值都是真值,包括对象、数组、日期等。甚至所有Symbol、空对象和数组都是真值。
Boolean(''); // false Boolean(0); // false Boolean(-0); // false Boolean(NaN); // false Boolean(null); // false Boolean(undefined); // false Boolean(false); // false
Boolean({}) // true Boolean([]) // true Boolean(Symbol()) // true Boolean(function() {}) // true
可以通过以下方式来过滤数组中的假值:
[0, "", " ", null, undefined, NaN].map(Boolean); // 输出结果:[false, false, true, false, false, false]
我们可以会遇到一种情况,当使用 5 == true
时,结果为false
,而使用if(5) {}
时,则 5 被认为是 true
并进入if/else
语句:
5 == true; // false if (5) { console.log('5'); // 5 };
这种情况下,即一个值和数字进行比较时,JavaScript 会试图将这个值转换为数字。所以,当比较5 == true
时,JavaScript 倾向于将true
转换为1,因为 1不等于5,因此结果为 false
。而在if(5) {}
的情况下,5 被转换为布尔值,而 5 是一个真值,所以它进入if
块。在这种情况下,可以选择显式转换以避免错误,因为 5 是一个真值,可以执行Boolean(5) == true
,这样就会返回true
了。
下面是 ECMAScript 规范中将数据类型转换为布尔值的规则:
ECMAScript 规范:262.ecma-international.org/5.1/#sec-9.…
彻底理解JavaScript中的类型转换(下)https://developer.aliyun.com/article/1411370