# js数据类型转换
# 转换的条件
js在以下情况下,会进行数据类型的转换:
- if条件运算符;
- !(取反操作),转布尔类型;
- 加减乘除(四则运算符号),其中
**+**
还可以拼接字符串; - '==' 或 '===' 比较,比较规则参考'==判断规则';
转换规则参考下表(来自红宝书):
对象类型的数据如何转字符串、数字,我们会在下面单独说明。
# 如何转换
# 1、取反运算符
转boolean值,规则参考上面的JavaScript类型转换参考表
。
# 2、条件运算符(if语句)
if语句,转boolean值,规则参考上面的JavaScript类型转换参考表
。
false、null、undefined、''(空字符串)、0(±0),NaN,都会转换为false,,其他为true。
# 3、四则运算符(+-*/)
注意:
1、**+**
不仅是四则运算,还可以做字符串拼接
。
2、-
, *
,/
都是进行正常的四则运算,四则运算会将非Number类型的转换为Number类型的值。
3、加法+
的特殊性,参考下方加号运算符章节,可以先看下这篇文章的介绍:JavaScript 加号运算符详解 (opens new window)。
# 加号运算符
作为一元运算符:
当+
作为一元运算符时,执行ToNumber() (opens new window)操作,规则如下图:
参数类型 | 返回值 |
---|---|
Undefiend | NaN |
Null | 0 |
Boolean | 如果是true,返回1。否则返回0 |
Number | 返回值本身 |
String | 1. 如果是纯数字字符串,返回转换后的数字 1. 如果是非纯数字,返回NaN |
Symbol | 报错TypeError,无法转换 |
Object | 转换步骤如下: 1. 执行ToPrimitive(input, hint),得到rs; 1. 返回ToNumber(rs)的结果 |
// " + " 作为一元运算符
// Date
var date = new Date();
console.log(+date); // 1619752121561
-> toPrimitive(date, number)
-> date.valueOf()得到一个时间戳: 1619752121561,它是一个非Object类型,然后执行toNumber操作
-> 1619752121561
// Array
var arr = [];
console.log(+arr); // 0
-> toPrimitive(arr, number)
-> arr.valueOf(),返回数组本身[],依然是一个对象
-> arr.toString(),返回空字符串,然后执行toNumber操作
-> 0
// 根据数组的ToPrimitive规则,数组元素为null或undefined时, 该元素被当做空字符串处理,所以[null]、[undefined]都会被转换为0。
console.log(+['123abc']); // NaN
console.log(+[null]); // 0
console.log(+[undefined]); // 0
// Object
var obj = {}, obj2 = {a: 1};
console.log(+obj, +obj2);// NaN
-> toPrimitive(obj, 'number')
-> arr.valueOf(),返回对象本身,依然是一个对象
-> arr.toString(),返回字符串"[object Object]", 然后执行toNumber操作
-> 非数字类的字符串,转数字,结果为NaN
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
作为二元运算符:
当+
作为二元运算符时,转换规则如下:
1) 值进行GetValue (opens new window)()操作,获取对象的值。
2) 值进行ToPrimitive (opens new window)()操作,转为原始类型。
3) 若一方为String类型,2个值都进行ToString (opens new window)()转换,最后进行字符串连接操作。
4) 若都不是String类型,2个值都进行ToNumber (opens new window)()转换,最后进行算数加法运算。
注意: +为一元运算符时: 执行ToPrimitive(input, PreferredType)时,PreferredType为"number"。 +为二元运算符时: 执行ToPrimitive(input, PreferredType)时,PreferredType为默认为"default"。 但是:Date类型内部重写了@@toPrimitive() (opens new window)方法,将 "default" 设置为 "string" ,而其他内置的对象都将 "default" 设置为 "number" 。
案例分析:
var obj = {
valueOf(){
return { a: 1 };
},
toString(){
return '100';
}
};
var res = 1 + obj;
// 双方都不是string,转number。
// obj转number -> 调用obj.valueOf(), 返回"{a:1}" -> 调用obj.toString(), 返回'100'
console.log(res, typeof res); // 1100, string
var d = new Date();
// 一方是string,都转string
// d转string时,由于Date重写了'@@primitive', 所以先调用toString(), 返回一个时间字符串 -> "1" + "字符串"
console.log("1" + d); // 1Fri Apr 30 2021 15:10:26 GMT+0800 (GMT+08:00)
// 双方都不是string,转number
// d转number时,由于Date重写了'@@primitive', 所以先调用toString(), 返回一个时间字符串 -> 1 + "字符串"
console.log(1 + d); // 1Fri Apr 30 2021 15:10:26 GMT+0800 (GMT+08:00)
var a = {}; b = [];
// 全部转基本类型:a->'[object Object]',b->'' --> '[object Object]'
console.log(a + b);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 关于ToPrimitive的说明
主要用于将一个对象转为一个原始值,js内部自动调用的。
**语法:**ToPrimitive (input[,PreferredType] )
参数:
- ① 参 input:传入的值。
- ② 参数 PreferredType:可选,需要被转换的类型。
- '+'加号作为一元运算符时,此值为
"number"
; - '+'作为二元运算符时,未传递此值,以默认的
"default"
代替。
- '+'加号作为一元运算符时,此值为
1) 若input类型为原始值(如:Undefined、Null、Boolean、Number、String、Symbol),直接返回input的本身。
2) 若input类型为object(如:Array、Object、Date),将根据第②个参数PreferredType的值进行以下操作:
对于+运算符: 1、作为一元运算符,PreferredType为'number'。 2、作为二元运算符: 1. Date重写了@@toPrimitive() (opens new window)方法,PreferredType值为'string'。 2. 其他对象PreferredType值为'number'。
# 双等号与三等号
js中,判断一个表达式两边是否相等时,我们可以使用双等号与三等号,可以看下mdn文档 (opens new window)中关于此部分的介绍。
# 双等号
判断规则:
- 如果两边类型相同,进入
===
判断; - 如果类型不同,则发生隐式转换:
- NaN和其他任何类型比较永远返回false(包括与自己比较)。
- null == undefined比较结果是true,除此之外,null、undefined和其他任何结果的比较值都为false。
- Boolean和其他任何类型比较,Boolean首先被转换为Number类型。
- String和Number比较,先将String转换为Number类型。
- 原始类型和引用类型
当原始类型和引用类型做比较时,对象类型会依照ToPrimitive (opens new window)规则转换为原始类型后再比较。
// 第一题
var obj = {
valueOf() {
return 3;
}
};
// 引用类型与原始类型比较
// -> obj转原始类型 -> obj.valueOf()返回3,
console.log(obj == 3); // 3== 3, true
console.log(obj == '3'); // 3 == '3'
2
3
4
5
6
7
8
9
10
11
我们看几个常见的面试考题:
1、[] == ![]
的结果是什么?
// 第二题
[] == ![];
// 1. !优先级高于==, 相当于[] == false;
// 2. 对象与普通值比较,对象转普通值。
// 2.1 先调用[].valueOf(),返回[],依然是对象;
// 2.3 再调用[].toString(),返回空字符串'';
// 3. 比较 '' == false,出现Boolean值,此时Boolean值转Number,相当于 '' == 0;
// 4. 字符串与数字比,string转number,空字符串转number为0,此时相当于 0 == 0
// 5. 返回true
2
3
4
5
6
7
8
9
2、[undefined] == false
的结果是什么?
- 第一步,对象转基本类型,[undefined]通过 valueOf ->toString 变成 '',
题目变成 '' == false
- 第二步: 布尔值转数字,false转为数字,题目变成 '' == 0
- 第三步,string转number,''转为数字0 ,题目变成 0 == 0
- 答案是 true
2
3
4
5
3、再来看一道题目:如何让a==1 && a==2 && a==3
成立?
我们可以利用js的隐式转换原理,重写对象的valueOf或者toString方法来实现。
// 可以这么做
var a = {
value: 0,
valueOf: function () {
return this.value += 1;
}
};
// 或者这么做
var a = {
value:[3,2,1],
valueOf: function () {
return this.value.pop();
}
};
console.log(a==1 && a==2 & a==3); // true
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 三等号
判断规则:
- 如果两边类型不同,则不相等;
- 如果类型相同:
- 如果是普通值(非引用类型),字符串、数字、布尔,值一样时相等。如果是对象,比较的是引用地址,地址一样才相等;
- 如果都是null或undefined,才相等,否则不等;
- 判断一个值是否是NaN,只能用
isNaN
方法; - 如果其中一个是NaN,则不相等;NaN不等于任何值,包括NaN自身;
NaN === NaN // false
// isNaN(NaN) // true
undefined === undefined // true
null === null // true
undefined === null // false
2
3
4
5
6