聊一聊JavaScript数据类型

JavaScript数据类型与存储机制:从基础到ES6新特性

JavaScript是一门动态类型语言,它的数据类型和存储机制是理解这门语言的核心之一。本文将带你深入探讨JavaScript的数据类型、堆栈存储机制,以及ES6中新增的数据类型和特性。无论你是初学者还是有一定经验的开发者,这篇文章都会为你提供新的见解。

1. JavaScript的数据类型

JavaScript的数据类型可以分为两大类:基本类型(Primitive Types)引用类型(Reference Types)

1.1 基本类型

基本类型是存储在栈内存中的简单数据段,它们的值直接存储在变量访问的位置。JavaScript中的基本类型包括:

  1. **number**:数字类型,包括整数和浮点数。

    1
    2
    let age = 27;
    let price = 9.99;
  2. **string**:字符串类型,表示文本数据。

    1
    let name = "Wang Yuxiang";
  3. **boolean**:布尔类型,表示逻辑值truefalse

    1
    let bol = true;
  4. **null**:表示一个空值或不存在的对象。

    1
    let empty = null;
  5. **undefined**:表示未定义的值。

    1
    2
    let unknown;
    console.log(unknown); // undefined
  6. **symbol**(ES6新增):表示唯一的、不可变的值,通常用作对象属性的键。

    1
    let id = Symbol("id");
  7. **bigint**(ES2020新增):表示任意精度的整数。

    1
    let bigNumber = 1234567890123456789012345678901234567890n;

1.2 引用类型

引用类型是存储在堆内存中的对象,变量中存储的是对象的引用地址。常见的引用类型包括:

  1. **object**:普通对象,用于存储键值对。

    1
    let person = { name: "Wang", age: 25 };
  2. **array**:数组,用于存储有序的数据集合。

    1
    let colors = ["red", "green", "blue"];
  3. **function**:函数,是可执行的对象。

    1
    2
    3
    function greet() {
    console.log("Hello!");
    }
  4. **dateregexp**等:内置对象。

    1
    2
    let now = new Date();
    let pattern = /abc/;

2. 堆栈存储机制

2.1 栈内存(Stack)

栈内存用于存储基本类型和引用类型的变量名(即引用地址)。它的特点是:

  • 空间较小:栈内存的分配和释放速度较快,但空间有限。
  • 自动管理:栈内存由系统自动分配和释放,遵循“后进先出”原则。

示例

1
2
3
4
let a = 10; // 基本类型,存储在栈内存
let b = a; // 复制值,b也是10
a = 20; // 修改a的值,b不受影响
console.log(b); // 10

2.2 堆内存(Heap)

堆内存用于存储引用类型的实际数据。它的特点是:

  • 空间较大:堆内存可以存储较大的数据,但分配和释放速度较慢。
  • 手动管理:堆内存由开发者或垃圾回收机制管理。

示例

1
2
3
4
let obj1 = { name: "Wang" }; // 引用类型,数据存储在堆内存
let obj2 = obj1; // 复制引用地址,obj2和obj1指向同一对象
obj1.name = "Yu"; // 修改obj1的属性,obj2也会受影响
console.log(obj2.name); // "Yu"

3. ES6新增的数据类型与特性

3.1 Symbol

Symbol是ES6引入的一种新的基本类型,用于创建唯一的、不可变的值。它通常用作对象属性的键,以避免属性名冲突。

1
2
3
4
5
6
7
8
9
10
11
let id1 = Symbol("id");
let id2 = Symbol("id");

console.log(id1 === id2); // false

let user = {
[id1]: 123,
name: "Wang"
};

console.log(user[id1]); // 123

3.2 MapSet

Map

Map是一种键值对集合,与普通对象不同,它的键可以是任意类型(包括对象)。

1
2
3
4
5
let map = new Map();
map.set("name", "Wang");
map.set(1, "number key");

console.log(map.get("name")); // "Wang"

Set

Set是一种值唯一的集合,常用于去重。

1
2
3
4
5
6
let set = new Set();
set.add(1);
set.add(2);
set.add(1); // 重复值会被忽略

console.log(set.size); // 2

3.3 WeakMapWeakSet

WeakMap

WeakMap是一种特殊的Map,它的键必须是对象,且不会阻止垃圾回收。

1
2
3
4
5
let weakMap = new WeakMap();
let obj = {};

weakMap.set(obj, "data");
console.log(weakMap.get(obj)); // "data"

WeakSet

WeakSet是一种特殊的Set,它的值必须是对象,且不会阻止垃圾回收。

1
2
3
4
5
let weakSet = new WeakSet();
let obj = {};

weakSet.add(obj);
console.log(weakSet.has(obj)); // true

3.4 BigInt

BigInt是ES2020引入的一种新的基本类型,用于表示任意精度的整数。

1
2
let bigNumber = 1234567890123456789012345678901234567890n;
console.log(bigNumber + 1n); // 1234567890123456789012345678901234567891n

4. 数据类型与存储机制的总结

特性 基本类型 引用类型
存储位置 栈内存 堆内存
存储内容 直接存储值 存储引用地址
复制行为 复制值 复制引用地址
修改影响 新旧变量互不影响 新旧变量共享同一对象
示例 numberstringbooleannull objectarrayfunction

5. 实际应用与建议

  1. 优先使用基本类型:基本类型的操作速度更快,占用内存更少。
  2. 谨慎使用引用类型:引用类型的复制和修改可能会影响其他变量,需要注意数据隔离。
  3. 利用ES6新特性SymbolMapSet等新特性可以解决许多传统JavaScript中的痛点。