Javascript数据类型

Javascript数据类型
MiloJavaScript 数据类型及实用技巧
原始类型/基本类型
在 JavaScript 中,有 7 种原始类型,分别是:
boolean
null
undefined
number
string
symbol
bigint
引用类型/复杂类型
引用类型包括:
- 对象(Object):由大括号
{}
包围的一组属性的集合。 - 数组(Array):由方括号
[]
包围的一组有序的值的集合。 - 函数(Function):可以执行特定操作的可重复使用的代码块。
- 日期(Date):表示日期和时间的对象。
- 正则表达式(RegExp):用于匹配和操作字符串的对象。
- Map:一种可迭代的键值对集合。
- Set:一种不重复值的集合。
基本类型和引用类型的区别
基本类型的值存储在栈中。当我们把 a
赋值给 b
的时候(b = a
),会开辟一块新的空间存储 b
的值。今后即使修改 a
的值,b
也不会改变。
引用类型存储的是对象的地址。假设把 obj1
赋值给 obj2
,只要我们修改其中一个变量所引用的对象时,其他引用该对象的变量也会受到影响。
如何判断一个变量类型,在不用 typeof
情况下
1 | console.log(Object.prototype.toString.call([1,2,3])); |
0.1+0.2等于多少
0.1+0.2 = 0.30000000000000000004
这是因为计算机以二进制存储,0.1这些数二进制是无限循环数,而为了舍弃后面的数,计算机会根据舍去第一位是1 or 0来判断非舍弃最后一位是否进位。
判断数组的四种方法
1 | console.log(Object.prototype.toString.call(b))//[object Array] |
console.log(['1','2','3'].map(parseInt))
输出是什么?
1 | // 输出为 1 NaN NaN |
undefined
与 null
的区别
undefined
表示变量已声明但未初始化。null
表示变量的值为“无”,即没有指向任何对象。
isNaN
与 Number.isNaN
区别
isNaN
会先将参数转换为数字,然后再检查是否为NaN
。Number.isNaN
则直接检查参数是否为NaN
,不会进行类型转换。
对象的浅拷贝有哪些?
1 | const obj1 = {a:1,b:2} |
数组的浅拷贝
1 | const arr1 = [1,2,3] |
深拷贝
使用
JSON.parse(JSON.stringify())
(简单但有局限性):1
let b = JSON.parse(JSON.stringify(a));
注意:这种方法不能处理函数、
undefined
、Date
、RegExp
等特殊类型,也不能处理循环引用,也不能复制对象中函数,不能复制原型链上的属性,会忽略symbol
和undefined
属性使用递归递实现(更通用):
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48function deepClone(source, clonedMap = new Map()) {
if(typeof source !== 'object' || source === null) {
return source;
}
//如果这个对象已经被拷贝过,直接从Map中返回
if(clonedMap.has(source)) {
return clonedMap.get(source);
}
let target;
if(Array.isArray(source)) {
target = [];
}
else if (source instanceof Date) {
target = new Date(source);
}
else if (source instanceof RegExp) {
target = new RegExp
}
else{
target = {}
}
//在Map中记录这个对象
clonedMap.set(source, target);
for(const key in source) {
if(Object.hasOwnProperty.call(source, key)) {
if(typeof source[key] === 'object'&& source[key] !== null) {
target[key] = deepClone(source[key], clonedMap);
}
else {
target[key] = source[key];
}
}
}
//克隆Symbol属性
const symbolKeys = Object.getOwnPropertySymbols(source);
for(const symbolKey of symbolKeys) {
target[symbolKey] = deepClone(source[symbolKey], clonedMap);
}
return target;
}
let b = deepClone(a);
for...in
和 for...of
的主要区别
特性 | for...in |
for...of |
---|---|---|
用途 | 遍历对象的可枚举属性(键名) | 遍历可迭代对象的值 |
适用对象 | 普通对象 | 数组、字符串、Map 、Set 等可迭代对象 |
遍历顺序 | 不保证顺序 | 保证顺序 |
是否访问原型链 | 会访问继承的属性(需结合 hasOwnProperty ) |
不访问继承的属性 |
是否适用于数组 | 不推荐(会遍历非数字键和继承属性) | 推荐(不会遍历非数字键和继承属性) |