目錄
JavaScript數據結構
一、基礎數據結構
1. 數組(Array)
2. 對象(Object)
二、ES6+ 高級數據結構
1. Map
2. Set
3. WeakMap 與 WeakSet
三、類型化數組(Typed Arrays)
四、其他數據結構實現
1. 棧(Stack)
2. 隊列(Queue)
3. 鏈表(Linked List)
五、數據結構選擇指南
六、最佳實踐
JavaScript中的for循環
1. 傳統?for?循環
語法
示例
特點
2.?for...of?循環
語法
示例
特點
3.?for...in?循環
語法
示例
特點
4.?Array.prototype.forEach
語法
示例
特點
5. 性能與選擇指南
性能對比
如何選擇?
6. 常見陷阱
1. 修改數組長度
2. 閉包問題
3. 遍歷稀疏數組
JavaScript數據結構
一、基礎數據結構
1. 數組(Array)
-
定義:有序元素集合,可存儲任意類型值。
-
創建方式:
let arr1 = [1, "a", true]; // 字面量 let arr2 = new Array(3); // 創建長度3的空數組(慎用)
-
核心方法:
-
增刪元素:
arr.push(4); // 末尾添加 → [1, 2, 3, 4] arr.pop(); // 移除末尾 → [1, 2] arr.unshift(0); // 開頭添加 → [0, 1, 2] arr.shift(); // 移除開頭 → [1, 2]
-
操作數組:
arr.splice(1, 1, "x"); // 從索引1刪除1個元素,插入"x" → [1, "x", 3] arr.slice(1, 3); // 截取索引1到3(不包含3)→ ["x", 3] arr.concat([4, 5]); // 合并數組 → [1, 2, 3, 4, 5]
-
迭代與轉換:
arr.map(x => x * 2); // 映射新數組 → [2, 4, 6] arr.filter(x => x > 1); // 過濾 → [2, 3] arr.reduce((sum, x) => sum + x, 0); // 累加 → 6
-
-
注意事項:
-
稀疏數組:空位(如?
new Array(3)
)可能引發意外行為。 -
引用類型:數組賦值傳遞引用,需用?
[...arr]
?或?arr.slice()
?克隆。
-
2. 對象(Object)
-
定義:鍵值對集合,鍵為字符串或 Symbol。
-
創建方式:
let obj1 = { name: "Alice", age: 25 }; // 字面量 let obj2 = new Object(); // 構造函數
-
核心操作:
-
增刪查改:
obj.email = "alice@example.com"; // 添加屬性 delete obj.age; // 刪除屬性 console.log("name" in obj); // 檢查屬性是否存在 → true
-
遍歷:
Object.keys(obj); // 返回鍵數組 → ["name", "email"] Object.values(obj); // 返回值數組 → ["Alice", "alice@example.com"] for (let key in obj) { console.log(key, obj[key]); } // 遍歷自身及原型鏈屬性
-
-
注意事項:
-
原型污染:避免修改?
Object.prototype
。 -
鍵順序:ES6 后字符串鍵按插入順序保留,但數字鍵優先排序。
-
二、ES6+ 高級數據結構
1. Map
-
特點:
-
鍵可以是任意類型(對象、函數等)。
-
保持插入順序。
-
-
核心方法:
let map = new Map(); map.set("key", "value"); // 添加鍵值對 map.get("key"); // 獲取值 → "value" map.has("key"); // 檢查存在 → true map.delete("key"); // 刪除鍵值對 map.size; // 獲取條目數
-
適用場景:需要復雜鍵或頻繁增刪鍵值對時,優于 Object。
2. Set
-
特點:存儲唯一值,自動去重。
-
核心方法:
let set = new Set(); set.add(1); // 添加值 set.add(2); set.has(1); // 檢查存在 → true set.delete(1); // 刪除值 set.size; // 獲取元素數量
-
適用場景:去重、集合運算(并集、交集等)。
3. WeakMap 與 WeakSet
-
特點:
-
弱引用:鍵必須是對象,不阻止垃圾回收。
-
不可迭代:無?
size
、clear()
?或遍歷方法。
-
-
使用場景:
-
WeakMap:存儲對象關聯的私有數據或元數據。
let wm = new WeakMap(); let obj = {}; wm.set(obj, "secret");
-
WeakSet:標記對象(如跟蹤已處理對象)。
let ws = new WeakSet(); ws.add(obj);
-
三、類型化數組(Typed Arrays)
用于處理二進制數據(如圖像、音頻),與?ArrayBuffer
?配合使用。
-
常見類型:
-
Int8Array
、Uint8Array
(8位整數) -
Int16Array
、Float32Array
?等。
-
-
示例:
let buffer = new ArrayBuffer(16); // 分配16字節內存 let int32View = new Int32Array(buffer); // 32位整數視圖(4個元素) int32View[0] = 42;
四、其他數據結構實現
JavaScript 未內置,但可通過基礎結構模擬:
1. 棧(Stack)
-
后進先出(LIFO),用數組實現:
class Stack {constructor() { this.items = []; }push(element) { this.items.push(element); }pop() { return this.items.pop(); }peek() { return this.items[this.items.length - 1]; } }
2. 隊列(Queue)
-
先進先出(FIFO):
class Queue {constructor() { this.items = []; }enqueue(element) { this.items.push(element); }dequeue() { return this.items.shift(); } // 時間復雜度 O(n) }
3. 鏈表(Linked List)
-
節點鏈接實現:
class Node {constructor(value) {this.value = value;this.next = null;} } class LinkedList {constructor() { this.head = null; }append(value) { /* 實現添加邏輯 */ } }
五、數據結構選擇指南
場景 | 推薦數據結構 | 理由 |
---|---|---|
有序集合,需快速訪問索引 | 數組(Array) | 索引操作時間復雜度 O(1) |
鍵值對,鍵為字符串或 Symbol | 對象(Object) | 語法簡潔,查找速度快 |
鍵為任意類型,需維護插入順序 | Map | 支持復雜鍵,有序 |
存儲唯一值 | Set | 自動去重,集合運算高效 |
高頻增刪元素(如隊列) | 鏈表(自定義實現) | 避免數組?shift() ?的 O(n) 復雜度 |
二進制數據處理 | 類型化數組(Typed Array) | 內存高效,適合底層操作 |
六、最佳實踐
-
優先使用 ES6+ 數據結構:如?
Map
、Set
?替代傳統對象和數組,提升代碼可讀性。 -
注意引用類型副作用:克隆數據避免意外修改。
-
性能敏感場景優化:如用?
Int32Array
?替代普通數組處理大量數值。 -
垃圾回收考慮:使用?
WeakMap
/WeakSet
?管理對象關聯數據,防止內存泄漏。
??
JavaScript中的for
循環
1. 傳統?for
?循環
最基礎的循環結構,通過明確的初始化、條件和迭代器控制循環。
語法
for (初始化; 條件; 迭代器) {// 循環體
}
示例
// 遍歷數組
const arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {console.log(arr[i]); // 輸出 1, 2, 3
}// 倒序循環
for (let i = arr.length - 1; i >= 0; i--) {console.log(arr[i]); // 輸出 3, 2, 1
}
特點
-
靈活控制:可自定義步長(如?
i += 2
)、跳過某次循環(continue
)或提前退出(break
)。 -
性能優化:預存數組長度(如?
let len = arr.length
)避免重復計算。 -
作用域:使用?
let
?聲明變量時,每次循環會創建新的塊級作用域。
2.?for...of
?循環
遍歷可迭代對象(如數組、字符串、Map、Set、生成器等)的值。
語法
for (const value of iterable) {// 使用 value
}
示例
const arr = ['a', 'b', 'c'];
for (const val of arr) {console.log(val); // 輸出 'a', 'b', 'c'
}// 遍歷字符串
for (const char of 'Hello') {console.log(char); // 輸出 H, e, l, l, o
}
特點
-
簡潔性:無需索引,直接獲取值。
-
支持異步:可與?
await
?結合使用(需在?async
?函數中)。 -
不適用于普通對象:默認對象不可迭代(除非自行實現?
Symbol.iterator
)。
3.?for...in
?循環
遍歷對象的可枚舉屬性(包括原型鏈上的屬性)。
語法
for (const key in object) {// 使用 key 訪問屬性值:object[key]
}
示例
const obj = { a: 1, b: 2 };
for (const key in obj) {console.log(key, obj[key]); // 輸出 a 1, b 2
}// 遍歷數組(不推薦!)
const arr = [1, 2, 3];
arr.foo = 'bar';
for (const key in arr) {console.log(key); // 輸出 0, 1, 2, 'foo'
}
特點
-
遍歷對象屬性:適合處理鍵值對。
-
可能遍歷原型鏈:需用?
hasOwnProperty
?過濾:for (const key in obj) {if (obj.hasOwnProperty(key)) {// 僅處理自身屬性} }
-
不保證順序:現代引擎通常按屬性添加順序遍歷,但復雜場景可能不一致。
4.?Array.prototype.forEach
數組專用的高階函數,遍歷每個元素。
語法
array.forEach((value, index, array) => {// 循環體
});
示例
const arr = [1, 2, 3];
arr.forEach((value, index) => {console.log(index, value); // 輸出 0 1, 1 2, 2 3
});
特點
-
不可中斷:無法使用?
break
?或?continue
,需通過?return
?跳過當前迭代。 -
鏈式調用:可與其他數組方法(如?
map
、filter
)配合。 -
異步陷阱:回調函數中的?
await
?不會暫停外層循環。
5. 性能與選擇指南
性能對比
-
最快:傳統?
for
?循環(尤其預存長度時)。 -
適中:
for...of
(底層使用迭代器協議)。 -
較慢:
forEach
(函數調用開銷)。
如何選擇?
場景 | 推薦方式 |
---|---|
需要索引或復雜控制 | 傳統?for ?循環 |
遍歷數組值(無需索引) | for...of |
遍歷對象屬性 | for...in ?+ 過濾 |
簡單數組操作 | forEach |
處理稀疏數組 | 傳統?for ?+ 判空 |
6. 常見陷阱
1. 修改數組長度
const arr = [1, 2, 3];
for (let i = 0; i < arr.length; i++) {arr.pop(); // 可能導致無限循環或跳過元素
}
2. 閉包問題
for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i)); // 輸出 3, 3, 3
}
// 解決:改用 let 或 IIFE
3. 遍歷稀疏數組
const arr = [1, , 3]; // 中間是空位
arr.forEach(v => console.log(v)); // 輸出 1, 3(跳過空位)
for (const v of arr) console.log(v); // 輸出 1, undefined, 3