问题:在JavaScript中一共有几种数据类型?
大白:这我熟啊,不就是number、bigint、string、 boolean、 null、 undefined、 symbol、object、array、function一共十种。
能轻松列举出十种数据类型,不错,你是高手。
但高手中的高手会这么回答:
数据类型分为简单(原始)数据类型和复杂数据类型,简单数据类型由:numeric、string、boolean、null、undefined、symbol六种,其中numeric就是将number和bigint归为一类叫做numeric,另外symbol和bigint是es6新增的数据类型;复杂数据类型有:object、array、function,但array和function都是object的子类型。也就是说,数据类型一共有七种。
面试官:有点东西~
然而只是能列出多少种数据类型对面试来说是远远不够的,下面来讲讲关于数据类型我们还需要了解的知识点。
为什么要分简单数据类型和复杂数据类型
根据数据类型的特性和内存分配方式,我们将它们分为简单数据类型(Primitive Types) 和复杂数据类型(Complex Types)。
JavaScript 的内存管理主要涉及两种内存区域:栈(Stack) 和 堆(Heap) 。这两种内存区域分别用于存储不同类型的值,从而影响变量的分配和访问方式。
栈(Stack)
栈是一种线性的数据结构,遵循后进先出(LIFO, Last In First Out)的原则。在 JavaScript 中,栈主要用于存储简单数据类型(也称作原始数据类型)的值。
简单数据类型的值直接存储在栈中,因为它们占用的内存空间相对较小且固定。当一个简单数据类型的值被赋给另一个变量时,实际上是进行了值的复制。例如:
let a = 10;
let b = a; // b 的值是 10,a 和 b 分别在栈中存储了独立的值
堆(Heap)
堆是一种非线性的数据结构,用于存储复杂数据类型(也称作引用数据类型)的值。
这些类型的值通常较大且不固定,因此它们被存储在堆中。栈中只存储指向堆中实际数据的引用。当一个复杂数据类型的值被赋给另一个变量时,实际上是复制了这个引用,而不是值本身。例如:
let obj1 = { name: "Alice" };
let obj2 = obj1; // obj2 存储的是 obj1 的引用,两者指向同一个对象
obj2.name = "Bob"; // 修改 obj2 的值也会改变 obj1 的值
console.log(obj1.name); // 输出 "Bob"
内存分配过程
-
声明变量:
- 当声明一个变量时,JavaScript 引擎会在栈中为该变量分配一小块内存,用于存储变量的名称和类型信息。
-
赋值:
- 如果赋值的是一个简单数据类型,值会直接存储在栈中。
- 如果赋值的是一个复杂数据类型,值会被存储在堆中,栈中存储的是指向堆中数据的引用。
-
传递参数:
- 当函数调用时,传递简单数据类型的参数会进行值的复制。
- 传递复杂数据类型的参数会复制引用,而不是值本身。
-
垃圾回收:
- JavaScript 引擎会自动管理内存,通过垃圾回收机制释放不再使用的内存。对于栈中的简单数据类型,当变量超出作用域时,其占用的内存会被自动释放。
- 对于堆中的复杂数据类型,当没有引用指向某个对象时,垃圾回收器会回收该对象占用的内存。
示例
// 简单数据类型
let num1 = 10;
let num2 = num1; // num2 的值是 10,num1 和 num2 分别在栈中存储了独立的值
// 复杂数据类型
let obj1 = { name: "Alice" };
let obj2 = obj1; // obj2 存储的是 obj1 的引用,两者指向同一个对象
obj2.name = "Bob"; // 修改 obj2 的值也会改变 obj1 的值
console.log(obj1.name); // 输出 "Bob"
// 函数调用
function changeValue(num, obj) {
num = 20; // 修改 num 的值不会影响外部的 num1
obj.name = "Charlie"; // 修改 obj 的值会影响外部的 obj1
}
changeValue(num1, obj1);
console.log(num1); // 输出 10
console.log(obj1.name); // 输出 "Charlie"
typeof
typeof
是 JavaScript 中的一个操作符,用于确定变量的数据类型。它可以返回一个表示变量类型的字符串。
let a = 1;
console.log(typeof a);
console.log(typeof "hello");
console.log(typeof true);
console.log(typeof 12n);
console.log(typeof Symbol());
console.log(typeof null);
console.log(typeof undefined);
console.log(typeof function () {});
运行结果:
发现了吗?typeof null
打印出来的结果是object
,这其实是一个早期遗留下来的bug,并且当检查数组时,typeof []
会返回 "object"
,这是因为数组在 JavaScript 中是对象的一种形式。如果需要特别检测一个值是否为数组,可以使用 Array.isArray()
方法。
小结
了解 JavaScript 的数据类型及其内存管理机制是每个开发者的基本功。通过合理利用简单数据类型和复杂数据类型,以及了解它们之间的区别,可以帮助我们编写出更加高效和易于维护的代码,下一篇我会详细介绍null、undefined、object以及es6新加入的symbol和bigint。
点个赞再走吧~