JS类型转换
2023-09-14 21:53:01 #JS

数据类型

基本类型

  • 名字和值都存储在栈内存中,按值访问,可以操作保存在变量中的实际的值
  • 六种基本类型:Number String Boolean Undefined Null Symbol
1
2
3
4
5
// 基本类型
let a = 100;
let b = a;
a = 200;
console.log(b); // 100

引用类型

  • 名字存储在栈内存中,值存储在堆内存中,操作的是变量的引用地址
  • 五种引用类型:Object Array Function RegExp Date
1
2
3
4
5
// 引用类型
let a = { age: 20 };
let b = a;
b.age = 21;
console.log(a.age); // 21
1
2
3
4
5
6
7
8
9
const obj1 = {
x: 100,
y: 200
}
const obj2 = obj1;
let x1 = obj1.x;
obj2.x = 101;
x1 = 102;
console.log(obj1); // {x: 101, y: 200}

typeof 操作符

  • 判断基本类型:Undefined Number String Boolean
  • 判断函数:Function
  • 识别引用类型(不可再细分):Object
1
2
3
4
5
6
typeof ccc             // 'undefined'
typeof console.log // 'function'
typeof function (){} // 'function'
typeof null // 'object'
typeof ['a', 'b'] // 'object'
typeof {x: 100} // 'object'

手写深拷贝

  • 默认情况下,基本类型都是深拷贝,引用类型都是浅拷贝
  • 浅拷贝复制的是对象的引用地址,因此克隆对象和原对象指向同一个地址,修改一个对象的属性,另一个对象的属性也随之改变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 浅拷贝
const obj1 = {
age: 20,
name: 'XXX',
address: {
city: 'guangzhou'
},
arr: ['a', 'b', 'c']
};

const obj2 = obj1;
obj2.address.city = 'shanghai';
obj2.arr[0] = 'a1';

console.log(obj1.address.city); // 'shanghai'
console.log(obj2.address.city); // 'shanghai'
console.log(obj1.arr[0]); // 'a1'
console.log(obj2.arr[0]); // 'a1'
  • 深拷贝,即对象以其引用的对象被复制时,复制所有字段以及复制字段所指向的动态分配内存,因此克隆对象和原对象的修改互不影响
1
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
/**
* 深拷贝
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj) {
// obj 是 null,或者不是对象和数组,直接返回
if (obj == null || typeof obj !== 'object') {
return obj;
}
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
// 不遍历其原型链上的属性
for (let key in obj) {
// 检查属性 key 在当前对象实例中(而不是在实例的原型中)存在
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key]);
}
}
// 返回结果
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const obj1 = {
age: 20,
name: 'XXX',
address: {
city: 'guangzhou'
},
arr: ['a', 'b', 'c']
};

const obj2 = deepClone(obj1);
obj2.address.city = 'shanghai';
obj2.arr[0] = 'a1';

console.log(obj1.address.city); // 'guangzhou'
console.log(obj2.address.city); // 'shanghai'
console.log(obj1.arr[0]); // 'a'
console.log(obj2.arr[0]); // 'a1'

类型转换

  • JavaScript 在声明时只有一种类型,只有到运行期间才会确定当前类型
  • 在运行期间,由于 JavaScript 没有对类型做严格限制,导致不同类型之间可以进行运算,因此需要允许类型之间互相转换

显式类型转换

  • 显式类型转换就是手动地将一种值转换为另一种值
  • 常用的显式类型转换方法有 NumberStringBooleanparseIntparseFloattoString

to boolean

使用 Boolean() 将其他类型的值转换为 Boolean 类型:

原始类型 转换结果
Undefined false
Null false
Number 0 和 NaN 返回 false,其他返回 true
String 空字符串返回 false,非空字符串返回 true
Symbol true
Object true
1
2
3
4
5
6
7
8
9
Boolean(undefined)       // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean('aaa') // true
Boolean(222) // true
Boolean(Symbol()) // true
Boolean({}) // true

to number

使用 Number() 将基本类型的值转换为 Number 类型:

原始类型 转换结果
Undefined NaN
Null 0
true 1
false 0
String 如果字符串中只包含数字,则转换为对应的数字
如果字符串中只包含十六进制格式,则转换为对应的十进制数字
如果字符串为空,则转换为 0
如果字符串包含上述之外的字符,则转换为 NaN
1
2
3
4
5
6
7
8
Number(undefined)         // NaN
Number(null) // 0
Number(true) // 1
Number(false) // 0
Number('111') // 111
Number('0x100F') // 4111
Number('') // 0
Number('abc123') // NaN

使用 Number() 将对象转换成 Number 类型:

  • 调用对象的 valueOf() 方法,没有则去原型链上查找
    • 如果 valueOf() 方法的返回值为原始值,则对返回值进行原始值 to number 的类型转换,得出转换结果
    • 如果 valueOf() 方法返回值是对象,则调用对象的 toString() 方法
      • 如果返回值为原始值, 则对返回值进行原始值 to number 的类型转换, 得出转换结果
      • 如果返回值为对象, 则报错
类型 toString valueOf
object “[object <type>]“ 指向自身
function 函数的字符串形式 指向自身
array “arr0, arr1, …” 或者 “” 指向自身
date 包含本地时间信息的字符串 从1970年1月1日开始至今的毫秒数
regexp 正则表达式的字符串形式 指向自身
error “<err>.name: <err>.message” 指向自身
1
2
3
4
5
6
7
8
9
Number({})                         // NaN
Number({a: 1}) // NaN
Number([]) // 0
Number([1]) // 1
Number([1, 2, 3]) // NaN
Number(function(){let a = 1}) // NaN
Number(new Date) // 1694697527729
Number(new Error('opps')) // NaN
Number(/\d+/g) // NaN

to string

使用 String() 将基本类型的值转换为 String 类型:

原始类型 转换结果
Undefined “undefined”
Null “null”
Number 相应数字的字符串类型
Boolean “true” or “false”
String String
1
2
3
4
5
String(undefined)       // undefined
String(null) // 'null'
String(123) // '123'
String(true) // 'true'
String(false) // 'false'

使用 String() 将对象转换为 String 类型:

  • 调用对象的toString()方法,没有则去原型链上查找
    • 如果 toString() 方法的返回值为原始值,则对返回值进行原始值 to string 的类型转换,得出转换结果

    • 如果 toString() 方法的返回值是对象,则调用对象的 valueOf() 方法

      • 如果返回值为原始值,则对返回值进行原始值 to string 的类型转换, 得出转换结果
      • 如果返回值为对象, 则报错
1
2
3
4
5
6
7
8
9
String({})                         // '[object Object]'
String({a: 1}) // '[object Object]'
String([]) // ''
String([1]) // '1'
String([1, 2, 3]) // '1,2,3'
String(function(){let a = 1}) // 'function(){let a = 1}'
String(new Date) // 'Thu Sep 14 2023 21:35:58 GMT+0800 (中国标准时间)'
String(new Error('opps')) // 'Error: opps'
String(/\d+/g) // '/\\d+/g'

隐式类型转换

+ 运算符

1
2
3
const a = 100 + 10;        // 110
const b = 100 + '10'; // '10010'
const c = true + '10'; // 'true10'

== 运算符

1
2
3
4
5
100 == '100';              // true
0 == ''; // true
0 == false; // true
false == ''; // true
null == undefined; // true

=== 运算符

注意!除了 == null 之外,其余一律使用 ===

1
2
3
4
5
6
const obj = {
x: 100
};
if (obj.a == null){}
// 等同于
// if (obj.a === null || obj.a === undefined) {}

逻辑运算符

1
2
3
console.log(10 && 0);       // 0
console.log('' || 'abc'); // abc
console.log(!window.abc); // true

逻辑判断

  • 经过两次非运算为 true 的变量为 truly 变量,反之为 falsely 变量
  • truly 变量:!!a === true 的变量
  • falsely 变量:!!a === false 的变量
1
2
3
4
5
6
7
// 以下是 falsely 变量,除此之外都是 truly 变量
!!0 === false
!!NaN === false
!!'' === false
!!null === false
!!undefined === false
!!false === false
  • if 语句判断的是 truly 变量,即只有 truly 变量才会进入 if 语句内
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// truly 变量
const a = true;
if (a) {
// ....
}
const b = 100;
if (b) {
// ....
}

// falsely 变量
const c = '';
if (c) {
// ....
}
const d = null;
if (d) {
// ....
}
let e;
if (e) {
// ....
}