JS中的数据类型
在 JavaScript 开发中,理解数据类型是基础且关键的一步。无论是日常编码还是面试场景,数据类型的细节都可能成为解决问题的关键。
一、简单值和复杂值
JavaScript 中的数据类型可分为两大类:简单值(基本类型)和复杂值(引用类型)。
(一)简单值
简单值包括以下七种:
- number:数字,例如
42
或3.14
。 - string:字符串,例如
"Hello, world!"
。 - boolean:布尔值,只有
true
和false
。 - undefined:未定义,表示变量已声明但未初始化。
- null:空值,表示没有对象。
- symbol:符号,用于创建唯一的标识符。
- bigint:大数,用于表示非常大的整数。
简单值的特点是它们无法再继续拆分。例如,一个数字或字符串是不可变的,你不能更改其内部结构。
注意点1:symbol 和 bigint
-
symbol:从 ES6 开始新增,主要用于创建唯一的标识符。例如:
const mySymbol = Symbol('mySymbol'); console.log(mySymbol); // Symbol(mySymbol)
Symbol 的值是唯一且不可变的,适用于作为对象属性的键。
-
bigint:从 ES2020 开始新增,用于表示大于
Number.MAX_SAFE_INTEGER
(即2^53 - 1
)或小于Number.MIN_SAFE_INTEGER
(即-2^53 + 1
)的整数。例如:const bigNumber = BigInt(1234567890123456789012345678901234567890n); console.log(bigNumber); // 1234567890123456789012345678901234567890n
注意点2:null 和 undefined
- null:表示对象的“无”,转为数值时会被转换为
0
,作为原型链的终点。 - undefined:表示简单值的“无”,转为数值为
NaN
。例如:console.log(null + 1); // 1 console.log(undefined + 1); // NaN
(二)复杂值
复杂值只有一种:object。对象可以包含多个简单值或复杂值。例如:
const obj = {name: "张三",age: 18,scores: {htmlScore: 99,cssScore: 95}
};
数组、函数、正则等也都是对象类型,属于复杂值。例如:
console.log(typeof []); // object
console.log(typeof function () {}); // function
console.log(typeof /abc/); // object
函数本质上也是对象,可以添加属性和方法。例如:
function func() {}
func.a = 1; // 添加属性
func.test = function () {console.log("This is a test function");
}; // 添加方法
console.log(func.a); // 1
func.test(); // This is a test function
二、两者之间本质区别
(一)内存存储
简单值存储在栈内存中,而复杂值存储在堆内存中。栈内存用于存储大小固定、生命周期短的数据,访问速度快;堆内存用于存储大小不固定、生命周期长的数据,访问速度较慢。
简单值直接存储数据的实际值,而复杂值存储的是内存地址。例如:
let a = 5; // 简单值存储在栈内存
let obj = {}; // 复杂值的地址存储在栈内存,具体数据存储在堆内存
(二)值传递
JavaScript 中只有值传递,没有引用传递。当传递复杂值时,传递的是内存地址的值。例如:
function test(obj) {obj.a = 1000; // 修改堆内存中的数据
}
const obj = {};
test(obj);
console.log(obj); // { a: 1000 }
但如果在函数内部重新赋值,会断开内外的联系:
function test(obj) {obj = { b: 1 }; // 重新赋值,断开联系obj.a = 1000;
}
const obj = {};
test(obj);
console.log(obj); // {}
三、两者之间行为区别
(一)访问方式
简单值直接按值访问,而复杂值需要通过内存地址访问具体数据。例如:
const str = "Hello"; // 简单值
console.log(str); // Helloconst obj = { name: "张三" }; // 复杂值
console.log(obj.name); // 张三
(二)比较方式
简单值直接比较值,而复杂值比较内存地址。例如:
const a = {}; // 内存地址 0x0012ff7c
const b = {}; // 内存地址 0x0012ff7d
console.log(a === b); // false
(三)动态属性
复杂值可以动态添加属性和方法,而简单值不行。例如:
const obj = {}; // 复杂值
obj.newProp = "newValue";
console.log(obj.newProp); // newValueconst a = 1; // 简单值
a.newProp = "newValue"; // 静默失败
console.log(a.newProp); // undefined
(四)变量赋值
简单值赋值时复制值,复杂值赋值时复制内存地址。例如:
let a = 5; // 简单值
let b = a;
b = 10; // 不影响 a
console.log(a); // 5
console.log(b); // 10let obj = {}; // 复杂值
let obj2 = obj;
obj2.name = "张三"; // 影响 obj
console.log(obj); // { name: '张三' }
console.log(obj2); // { name: '张三' }
四、面试题解析
(一)JS 中的数据类型有哪些?基本类型和引用类型的区别是什么?
- 基本类型:包括
number
、string
、boolean
、undefined
、null
、symbol
和bigint
。它们存储在栈内存中,访问速度快,赋值时复制值。 - 引用类型:只有
object
。它们存储在堆内存中,访问速度较慢,赋值时复制内存地址。
(二)为什么 null
的数据类型打印出来为 object
?
这是 JavaScript 设计上的一个遗留问题。最初,null
被表示为全零(00000000),这使得 typeof null
的结果与对象一致。虽然这个行为在技术上是不正确的,但由于向后兼容性的考虑,这个设计决策一直未被修改。
(三)为什么 undefined
和 null
明明是两种基础数据类型,但 undefined == null
返回的是 true
?
这是 JavaScript 借鉴其他语言的一个设计。null
表示对象的“无”,而 undefined
表示简单值的“无”。在 JavaScript 中,null
可以自动转为 0
,而 undefined
不能。因此,undefined == null
返回 true
是为了保持与其他语言的一致性。