《数据类型转换》
数据类型介绍: 《数据类型》
将值从一种类型转换为另一种类型通常称为类型转换(type casting),这是显式的情况;隐式的情况称为强制类型转换(coercion)
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时(runtime)。
强制类型转换又分以下两种:
- 显式强制类型转换(explicit coercion)
- 隐式强制类型转换(implicit coercion)
# 抽象操作
“抽象操作”(即“仅供内部使用的操作”),是js的内置函数
# String()
处理非字符串到字符串的强制类型转换。对基本类型有效,对引用类型(object)无效。
String(12); // "12"
String("haha"); // "haha"
String(null); // "null"
String(undefined); // "undefined"
String(true); // "true"
String({a: '12'}); // [object Object]
2
3
4
5
6
value值 | 原始类型 | 转换后 |
---|---|---|
12 | number | "12" |
haha | string | "haha" |
null | null | "null" |
undefined | undefined | "undefined" |
true | boolean | "true" |
{a: '12'} | object | [object Object] |
# JSON.stringify(..)
JSON 字符串化和 toString() 的效果基本相同,只不过序列化的结果总是字符串。
1. 安全的 JSON 值转换
JSON.stringify(12); // "12"
JSON.stringify("str"); // ""str""
JSON.stringify(null); // "null"
JSON.stringify(true); // "true"
JSON.stringify({a: '12'}); // "{"a":"12"}"
2
3
4
5
value值 | 原始类型 | 转换后 |
---|---|---|
12 | number | "number" |
haha | string | ""haha"" (含有双引号的字符串) |
null | null | "null" |
true | boolean | "true" |
{a: '12'} | object | "{"a":"12"}" |
2. 不安全的 JSON 值转换
JSON.stringify(..) 在对象中遇到 undefined
、function
和 symbol
时会自动将其忽略,在
数组中则会返回 null
(以保证单元位置不变)。
JSON.stringify( undefined ); // undefined
JSON.stringify( function(){} ); // undefined
JSON.stringify(
[ 1, undefined, function(){}, 4]
); // "[1, null, null, 4]"
JSON.stringify(
{ a:2, b:function(){} }
); // "{"a":2}
2
3
4
5
6
7
8
对包含循环引用的对象执行 JSON.stringify(..) 会出错
var o = { };
var a = {
b: 42,
c: o, // 循环引用
d: function(){}
};
// 在a中创建一个循环引用
o.e = a;
// 循环引用在这里会产生错误
// JSON.stringify( a );
// JSON.stringify( o );
2
3
4
5
6
7
8
9
10
11
3. 自定义 JSON 序列化
var a = {
b: 42,
c: 'haha',
d: function(){}
};
// 自定义的JSON序列化
a.toJSON = function() {
// 序列化仅包含b
return { b: this.b };
};
JSON.stringify( a ); // "{"b":42}"
2
3
4
5
6
7
8
9
10
11
12
13
# Number()
处理非数字值到数字的强制类型转换, 处理失败时返回NaN。
Number("33"); // 33
Number(null); // 0
Number(undefined); // NaN
Number(true); // 1
Number(false); // 0
Number({a: '12'}); // NaN
Number(function(){}); // NaN
2
3
4
5
6
7
8
value值 | 原始类型 | 转换后value值 |
---|---|---|
"33" | string | 33 |
null | null | 0 |
undefined | undefined | NaN |
true | boolean | 1 |
false | boolean | 0 |
{a: '12'} | object | NaN |
八进制和十六进制
- 如果前缀为 0,则 JavaScript 会把数值常量解释为八进制数
- 如果前缀为 0 和 "x",则解释为十六进制数
// 八进制的377 -> 十进制255
Number(0377); // 255
// 十六进制 -> 十进制的255
Number(0xFF); // 255
2
3
4
对象和数组
对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
为了将值转换为相应的基本类型值,抽象操作会检查该值是否有 valueOf()
方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString()
的返回值(如果存在)来进行强制类型转换。如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。
从 ES5 开始,使用 Object.create(null) 创建的对象 [[Prototype]] 属性为 null,并且没有 valueOf() 和 toString() 方法,因此无法进行强制类型转换。
var a = {
valueOf: function(){
return "42";
}
};
var b = {
toString: function(){
return "42";
}
};
var c = [4,2];
c.toString = function(){
return this.join( "" ); // "42"
};
Number( a ); // 42
Number( b ); // 42
Number( c ); // 42
Number( "" ); // 0
Number( [] ); // 0
Number( [ "abc" ] ); // NaN
Number(['1']); // 1
Number(['1', '2']); // NaN
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Boolean()
除了假值和假值对象,其他的都可以看做是真值。
// 假值
Boolean(""); // false
Boolean(undefined); // false
Boolean(null); // false
Boolean(false); // false
Boolean(+0); // false
Boolean(-0); // false
Boolean(0); // false
Boolean(NaN); // false
// 假值对象(浏览器自己创建的对象)
Boolean(document.all) // false
...
// 真值
Boolean([]); // true
Boolean({}); // true
Boolean(function(){}); // true
Boolean(1) // true
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 显式强制类型转换
# 字符串与数字
# 1. String() 和 Number()
# 2. toString()
toString() 是显式的,不过其中涉及隐式转换。因为toString() 对 number 这样的基本类型值不适用,所以 JavaScript 引擎会自动为 number 类型创建一个封装对象,然后对该对象调用 toString()。这里显式转换中含有隐式转换。
var a = 42;
a.toString(); // "42"
2
# 3. 一元运算 +
和 -
一元运算 + 被普遍认为是显式强制类型转换
var c = "3.14";
var d = +c;
var e = -c; // 会反转符号位
var f = - -c; // 中间要有空格
d; // 3.14
e; // -3.14
f; // 3.14
// 日期显式转换为数字
var d = new Date;
+d; // 时间戳 1595836134918
// 更好的办法(建议使用)
var timestamp = Date.now()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 4. ~
运算符(非)
~
运算符(位非)用于对一个二进制操作数逐位进行取反操作。
- 第 1 步:把运算数转换为 32 位的二进制整数。
- 第 2 步:逐位进行取反操作。
- 第 3 步:把二进制反码转换为十进制浮点数。
~12; // -13
~
和 indexOf() 结合使用
var a = "Hello World";
if (~a.indexOf( "lo" )) { // -4 -> 真值 -> true
// 找到匹配!
}
if (!~a.indexOf( "ol" )) { // -4 -> 真值 -> true
// 没有找到匹配!
}
2
3
4
5
6
7
8
9
# 显式解析数字字符串
- Number():将非数字值转换为数字,处理失败时返回NaN
- parseInt(): 仅针对字符串值,其他类型无效,返回一个整数
- parseFloat():作用和parseInt() 一致,但可返回浮点数
var a = "42";
var b = "42px";
Number( a ); // 42
parseInt( a ); // 42
Number( b ); // NaN
parseInt( b ); // 42
var c = '12.3333'
parseInt( c ); // 12
parseFloat( c ); // 12.3333
2
3
4
5
6
7
8
9
10
11
12
# 显式转换为布尔值
# 1. Boolean()
# 2. !!
一元运算符 ! 显式地将值强制类型转换为布尔值,它同时还将真值反转为假值(或假值反转为真值)。
显式强制类型转换为布尔值最常用的方强制类型转换方法是 !!
,因为第二个 ! 会将结果反转回原值。
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g; // undefined
!!a; // true
!!b; // true
!!c; // true
!!d; // false
!!e; // false
!!f; // false
!!g; // false
2
3
4
5
6
7
8
9
10
11
12
13
14
15
value值 | Boolean()转换 | !!转换 |
---|---|---|
"" | false | false |
0 | false | false |
null | false | false |
undefined | false | false |
"0" | true | true |
[] | true | true |
{} | true | true |
在 if(..).. 这样的布尔值上下文中,如果没有使用 Boolean(..) 和 !!,就会自动隐式地进行 ToBoolean 转换。
# 隐式强制类型转换
# 自动转换类型
当 JavaScript 尝试操作一个 "错误" 的数据类型时,会自动转换为 "正确" 的数据类型。
5 + null // 返回 5 null 转换为 0
"5" + null // 返回"5null" null 转换为 "null"
"5" + 1 // 返回 "51" 1 转换为 "1"
"5" - 1 // 返回 4 "5" 转换为 5
"5" * true // 返回 5 "true" 转换为 1
2
3
4
5
# 自动转换为字符串
当你尝试输出一个对象或一个变量时 JavaScript 会自动调用变量的 toString() 方法:
document.getElementById("demo").innerHTML = myVar;
myVar = {name:"Fjohn"} // toString 转换为 "[object Object]"
myVar = [1,2,3,4] // toString 转换为 "1,2,3,4"
myVar = new Date() // toString 转换为 "Fri Jul 18 2014 09:08:55 GMT+0200"
2
3
4
5
数字和布尔值也经常相互转换:
myVar = 123 // toString 转换为 "123"
myVar = true // toString 转换为 "true"
myVar = false // toString 转换为 "false"
2
3
# 类型转换小结
下表展示了使用不同的数值转换为数字(Number), 字符串(String), 布尔值(Boolean):
原始值 | 转换为数字 | 转换为字符串 | 转换为布尔值 |
---|---|---|---|
false | 0 | ""false"" | false |
true | 1 | "true" | true |
0 | 0 | "0" | false |
1 | 1 | "1" | true |
"0" | 0 | "0" | true |
"000" | 0 | "000" | true |
"1" | 1 | "1" | true |
NaN | NaN | "NaN" | false |
"" | 0 | "" | false |
[ ] | 0 | "" | true |
function(){} | NaN | "function(){}" | true |
{ } | NaN | "[object Object]" | true |
null | 0 | "null" | false |
undefined | NaN | "undefined" | false |
Infinity | Infinity | "Infinity" | true |
-Infinity | -Infinity | "-Infinity" | true |
# 经典面试题
1 + '1'
true + 0
{}+[]
4 + {}
4 + [1]
'a' + + 'b'
console.log ( [] == 0 )
console.log ( ! [] == 0 )
console.log ( [] == ! [] )
console.log ( [] == [] )
console.log({} == !{})
console.log({} == {})
2
3
4
5
6
7
8
9
10
11