在 JavaScript 中,数据结构的选择和实现对于编写高效、可维护的代码至关重要。JavaScript 提供了一系列内置的数据结构,同时也支持自定义复杂的数据结构。以下是 JavaScript 中常用的一些数据结构及其基本介绍:
内置数据结构
1. 数组(Array)
数组是一种线性数据结构,用于存储一系列有序的元素。JavaScript 的数组实际上是对象,支持动态增长和索引访问。
特点:
- 动态大小
- 索引访问
- 支持多种内置方法(如
push
,pop
,shift
,unshift
,splice
等)
示例:
javascript
let arr = [1, 2, 3];
arr.push(4); // 添加元素
console.log(arr.pop()); // 移除并返回最后一个元素
console.log(arr[0]); // 访问第一个元素
2. 字符串(String)
字符串是不可变的字符序列,通常用于表示文本信息。JavaScript 中的字符串可以用单引号或双引号表示。
特点:
- 不可变性
- 索引访问
- 支持多种内置方法(如
split
,join
,trim
等)
示例:
javascript
let str = "Hello, world!";
console.log(str.split(", ")[1]); // 分割字符串
3. 对象(Object)
对象是一种键值对集合,用于存储和管理相关联的数据。JavaScript 中的对象是哈希表的实现形式,提供了灵活的数据存储机制。
特点:
- 键值对存储
- 动态属性
- 支持原型继承
示例:
javascript
let obj = { name: "Alice", age: 30 };
console.log(obj.name); // 访问属性
obj.age = 31; // 修改属性
4. Map
Map
是 ES6 引入的新数据结构,类似于对象,但它允许任何类型(对象或者原始值)的值作为键。
特点:
- 键值对存储
- 支持迭代器协议
- 任何值(对象或者原始值)都可以作为键或值
示例:
javascript
const myMap = new Map();
const keyString = "a string";
const keyObj = {};
const keyFunc = function () {};
// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键 keyObj 关联的值");
myMap.set(keyFunc, "和键 keyFunc 关联的值");
console.log(myMap.size); // 3
// 读取值
console.log(myMap.get(keyString)); // "和键'a string'关联的值"
console.log(myMap.get(keyObj)); // "和键 keyObj 关联的值"
console.log(myMap.get(keyFunc)); // "和键 keyFunc 关联的值"
console.log(myMap.get("a string")); // "和键'a string'关联的值",因为 keyString === 'a string'
console.log(myMap.get({})); // undefined,因为 keyObj !== {}
console.log(myMap.get(function () {})); // undefined,因为 keyFunc !== function () {}
5. Set
Set
是 ES6 引入的新数据结构,用于存储唯一的值集合。
特点:
- 值的唯一性
- 支持迭代器协议
示例:
javascript
let set = new Set([1, 2, 3]);
set.add(4);
console.log(set.has(3)); // 判断是否存在
6. WeakMap 和 WeakSet
WeakMap
和 WeakSet
是 ES6 引入的弱引用版本的数据结构,主要用于存储临时数据。
特点:
- 键值对存储(
WeakMap
) - 值的唯一性(
WeakSet
) - 键或值可以被垃圾回收
示例:
javascript
let weakMap = new WeakMap();
let obj = {};
weakMap.set(obj, "some data");
console.log(weakMap.get(obj)); // 获取值
自定义数据结构
除了内置的数据结构外,JavaScript 还支持自定义复杂的数据结构,例如:
1. 链表(LinkedList)
链表是一种线性数据结构,其中每个元素(节点)包含数据和指向下一个节点的指针。
特点:
- 动态大小
- 无需连续内存空间
- 插入和删除操作效率高
示例:
javascript
class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
}
append(data) {
let newNode = new Node(data);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
}
}
let list = new LinkedList();
list.append(1);
list.append(2);
2. 栈(Stack)
栈是一种后进先出(LIFO)的数据结构,通常用于实现函数调用栈。
特点:
- 后进先出
- 支持压栈(push)和弹栈(pop)
示例:
javascript
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
if (this.isEmpty()) return undefined;
return this.items.pop();
}
isEmpty() {
return this.items.length === 0;
}
}
let stack = new Stack();
stack.push(1);
stack.push(2);
console.log(stack.pop()); // 输出 2
3. 队列(Queue)
队列是一种先进先出(FIFO)的数据结构,通常用于实现任务调度。
特点:
- 先进先出
- 支持入队(enqueue)和出队(dequeue)
示例:
javascript
class Queue {
constructor() {
this.items = [];
}
enqueue(element) {
this.items.push(element);
}
dequeue() {
if (this.isEmpty()) return undefined;
return this.items.shift();
}
isEmpty() {
return this.items.length === 0;
}
}
let queue = new Queue();
queue.enqueue(1);
queue.enqueue(2);
console.log(queue.dequeue()); // 输出 1
总结
选择合适的数据结构取决于具体的应用场景。内置数据结构如数组、对象、Map 和 Set 提供了方便的工具来处理常见问题,而自定义数据结构如链表、栈和队列则适用于特定的需求。理解每种数据结构的特点和适用场景是编写高效代码的关键。