第一章:语法增强篇 --- 从"语法糖"到语言哲学
一、解构赋值(Destructuring Assignment)
背景动机: 在 ES5 时代,数据提取是重复又冗长的:
js
var user = { name: "Alice", age: 25 };
var name = user.name;
var age = user.age;
ES6 引入了解构赋值,提升代码可读性与语义化表达:
js
const { name, age } = user;
设计目的: 减少样板代码(Boilerplate),引入"模式匹配"思维。
二、模板字符串(Template Literals)
解决的问题: 传统字符串拼接冗长且不直观:
js
console.log("Hello, " + user.name + "! You are " + user.age + " years old.");
模板字符串让表达式嵌入变得自然:
js
console.log(`Hello, ${user.name}! You are ${user.age} years old.`);
Mermaid 图示:
第二章:新数据结构篇 --- 构建现代应用的数据基石
一、Map 与 WeakMap:超越 Object 的键值存储
背景与动机
ES5 Object 的局限性: 在 ES5 时代,JavaScript 只有 Object 可用于键值存储,但存在诸多问题:
javascript
// 传统 Object 的问题示例
const user = { name: "Alice" };
// 1. 键只能是字符串或 Symbol
const obj = {};
obj[user] = "user object"; // 键被转换为 "[object Object]"
console.log(obj["[object Object]"]); // "user object" - 非预期行为
// 2. 原型链污染风险
const data = JSON.parse('{"__proto__": {"isAdmin": true}}');
console.log({}.isAdmin); // true - 安全漏洞!
// 3. 无法保证插入顺序
const unordered = { z: 1, a: 2 };
console.log(Object.keys(unordered)); // ["z", "a"] - 顺序不确定
Map 的设计哲学: ES6 引入 Map 来解决这些问题,它不仅仅是语法糖,而是重新设计的存储结构:
javascript
const map = new Map();
// 任意类型作为键
const user = { name: "Alice" };
map.set(user, "user object");
console.log(map.get(user)); // "user object" - 预期行为
// 无原型链风险
map.set("__proto__", "safe value");
console.log(map.get("__proto__")); // "safe value"
// 保持插入顺序
map.set("z", 1).set("a", 2);
console.log([...map.keys()]); // [user, "z", "a"] - 保持插入顺序
核心特性与使用方法
基础 API 操作:
javascript
// 创建与初始化
const map = new Map([
["name", "Alice"],
["age", 25],
[{ id: 1 }, "object key"]
]);
// 基本操作
console.log(map.size); // 3
map.set("city", "Beijing");
console.log(map.has("name")); // true
console.log(map.get("name")); // "Alice"
map.delete("age");
map.clear();
// 遍历方法
map.forEach((value, key) => {
console.log(`${key}: ${value}`);
});
for (let [key, value] of map.entries()) {
console.log(key, value);
}
高级使用模式:
javascript
// 1. 对象元数据存储
const userMetadata = new Map();
const users = [{ id: 1 }, { id: 2 }];
users.forEach(user => {
userMetadata.set(user, {
createdAt: new Date(),
accessCount: 0,
lastActive: null
});
});
// 2. 函数缓存(Memoization)
function expensiveOperation(n) {
if (!expensiveOperation.cache) {
expensiveOperation.cache = new Map();
}
if (expensiveOperation.cache.has(n)) {
return expensiveOperation.cache.get(n);
}
const result = n * n; // 模拟复杂计算
expensiveOperation.cache.set(n, result);
return result;
}
// 3. 配置管理
class ConfigManager {
constructor() {
this.config = new Map();
this.defaults = new Map([
["timeout", 5000],
["retries", 3]
]);
}
set(key, value) {
this.config.set(key, value);
return this;
}
get(key) {
return this.config.has(key) ? this.config.get(key) : this.defaults.get(key);
}
}
底层原理与性能分析
内部实现机制: Map 在 JavaScript 引擎中通常使用哈希表实现,但做了特殊优化:
javascript
// 伪代码展示 Map 内部结构
class HashMap {
constructor() {
this.buckets = new Array(16); // 初始桶数量
this.size = 0;
}
// 哈希函数处理各种类型
#hashKey(key) {
if (typeof key === "object") {
return `object:${System.identityHashCode(key)}`;
}
return `${typeof key}:${key}`;
}
set(key, value) {
const hash = this.#hashKey(key);
const bucketIndex = hash % this.buckets.length;
// 处理哈希冲突(链地址法)
if (!this.buckets[bucketIndex]) {
this.buckets[bucketIndex] = [];
}
const bucket = this.buckets[bucketIndex];
for (let i = 0; i < bucket.length; i++) {
if (bucket[i].key === key) {
bucket[i].value = value;
return;
}
}
bucket.push({ key, value });
this.size++;
// 动态扩容
if (this.size / this.buckets.length > 0.75) {
this.#resize();
}
}
}
性能基准测试:
javascript
// Map vs Object 性能对比
const ITERATIONS = 100000;
// 插入性能
console.time("Map insert");
const map = new Map();
for (let i = 0; i < ITERATIONS; i++) {
map.set(`key${i}`, i);
}
console.timeEnd("Map insert");
console.time("Object insert");
const obj = {};
for (let i = 0; i < ITERATIONS; i++) {
obj[`key${i}`] = i;
}
console.timeEnd("Object insert");
// 查找性能
console.time("Map lookup");
for (let i = 0; i < ITERATIONS; i++) {
map.get(`key${i}`);
}
console.timeEnd("Map lookup");
console.time("Object lookup");
for (let i = 0; i < ITERATIONS; i++) {
const _ = obj[`key${i}`];
}
console.timeEnd("Object lookup");
Mermaid 图示:Map 内部结构
WeakMap:弱引用与内存管理
设计目的: WeakMap 专门解决对象作为键时的内存泄漏问题:
javascript
// 传统 Map 的内存泄漏问题
let user = { name: "Alice" };
const map = new Map();
map.set(user, "some data");
// 即使不再需要 user,Map 仍然持有引用
user = null;
console.log(map.size); // 1 - 内存无法回收
// WeakMap 解决方案
let user2 = { name: "Bob" };
const weakMap = new WeakMap();
weakMap.set(user2, "some data");
user2 = null;
// weakMap 中的条目会被自动垃圾回收
使用场景与限制:
javascript
// 1. 私有属性模拟
const privateData = new WeakMap();
class User {
constructor(name) {
privateData.set(this, {
name,
secret: Math.random()
});
}
getName() {
return privateData.get(this).name;
}
// 外部无法访问 secret
}
// 2. DOM 元素元数据
const domMetadata = new WeakMap();
function setupElement(element) {
domMetadata.set(element, {
clickCount: 0,
lastClick: null
});
element.addEventListener("click", () => {
const data = domMetadata.get(element);
data.clickCount++;
data.lastClick = new Date();
});
}
// WeakMap 的限制
console.log(weakMap.size); // undefined - 没有 size 属性
// weakMap.keys() // 错误 - 不可遍历
实战应用案例
案例1:响应式系统依赖跟踪
javascript
class ReactiveSystem {
constructor() {
this.dependencies = new Map();
this.targetMap = new WeakMap();
}
track(target, key) {
if (!this.targetMap.has(target)) {
this.targetMap.set(target, new Map());
}
const depsMap = this.targetMap.get(target);
if (!depsMap.has(key)) {
depsMap.set(key, new Set());
}
const dep = depsMap.get(key);
dep.add(currentEffect);
}
trigger(target, key) {
const depsMap = this.targetMap.get(target);
if (depsMap && depsMap.has(key)) {
depsMap.get(key).forEach(effect => effect());
}
}
}
案例2:LRU 缓存实现
javascript
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (!this.cache.has(key)) {
return -1;
}
// 提升为最近使用
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 删除最久未使用
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}
性能优化与最佳实践
优化策略:
javascript
// 1. 批量操作优化
class OptimizedMap extends Map {
setMultiple(entries) {
// 避免多次触发可能的观察者
for (const [key, value] of entries) {
super.set(key, value);
}
}
// 2. 预分配容量(某些引擎优化)
ensureCapacity(minCapacity) {
// 实际实现依赖具体引擎
}
}
// 3. 选择合适的键类型
const stringKeys = new Map(); // 最快
const numberKeys = new Map(); // 次之
const objectKeys = new Map(); // 较慢但功能强大
使用决策树:
二、Set 与 WeakSet:唯一值的高效管理
背景与设计哲学
传统数组去重的问题:
javascript
// ES5 数组去重方案
function uniqueArray(arr) {
const result = [];
for (let i = 0; i < arr.length; i++) {
if (result.indexOf(arr[i]) === -1) {
result.push(arr[i]);
}
}
return result;
}
// 时间复杂度 O(n²),性能差
const numbers = [1, 2, 2, 3, 4, 4, 5];
console.log(uniqueArray(numbers)); // [1, 2, 3, 4, 5]
Set 的解决方案:
javascript
// ES6 Set 去重
const numbers = [1, 2, 2, 3, 4, 4, 5];
const unique = [...new Set(numbers)];
// 时间复杂度 O(n),性能优异
核心特性与 API
基础操作:
javascript
// 创建与初始化
const set = new Set([1, 2, 3, 4, 4]);
console.log(set.size); // 4 - 自动去重
// 基本操作
set.add(5);
set.add(5); // 重复添加无效
console.log(set.has(3)); // true
set.delete(2);
console.log(set.size); // 3
// 遍历方法
set.forEach(value => {
console.log(value);
});
for (let value of set.values()) {
console.log(value);
}
高级集合操作:
javascript
class ExtendedSet extends Set {
// 并集
union(otherSet) {
return new ExtendedSet([...this, ...otherSet]);
}
// 交集
intersection(otherSet) {
return new ExtendedSet([...this].filter(x => otherSet.has(x)));
}
// 差集
difference(otherSet) {
return new ExtendedSet([...this].filter(x => !otherSet.has(x)));
}
// 对称差集
symmetricDifference(otherSet) {
return this.union(otherSet).difference(this.intersection(otherSet));
}
// 子集判断
isSubset(otherSet) {
return [...this].every(x => otherSet.has(x));
}
}
// 使用示例
const setA = new ExtendedSet([1, 2, 3]);
const setB = new ExtendedSet([2, 3, 4]);
console.log([...setA.union(setB)]); // [1, 2, 3, 4]
console.log([...setA.intersection(setB)]); // [2, 3]
console.log([...setA.difference(setB)]); // [1]
底层实现与性能分析
内部哈希机制:
javascript
// Set 内部简化实现
class HashSet {
constructor(iterable = []) {
this.values = new Map();
for (const value of iterable) {
this.add(value);
}
}
add(value) {
this.values.set(value, value);
return this;
}
has(value) {
return this.values.has(value);
}
delete(value) {
return this.values.delete(value);
}
get size() {
return this.values.size;
}
// 迭代器
*[Symbol.iterator]() {
yield* this.values.keys();
}
}
性能基准:
javascript
// Set vs Array 性能对比
const SIZE = 100000;
// 查找性能
const set = new Set();
const array = [];
for (let i = 0; i < SIZE; i++) {
set.add(i);
array.push(i);
}
console.time("Set lookup");
for (let i = 0; i < SIZE; i++) {
set.has(i);
}
console.timeEnd("Set lookup");
console.time("Array includes");
for (let i = 0; i < SIZE; i++) {
array.includes(i);
}
console.timeEnd("Array includes");
Mermaid 图示:Set 操作关系
A ∪ B] B --> E[交集 Intersection
A ∩ B] B --> F[差集 Difference
A - B] B --> G[对称差集
A Δ B] H[Set 特性] --> I[唯一性保证] H --> J[快速查找 O1] H --> K[保持插入顺序] H --> L[迭代友好]
WeakSet:弱引用集合
设计目的与使用场景:
javascript
// 1. 对象标记
const markedObjects = new WeakSet();
function processObject(obj) {
if (markedObjects.has(obj)) {
console.log("对象已处理过");
return;
}
// 处理对象...
markedObjects.add(obj);
}
// 2. 防止循环引用
class TreeNode {
constructor(value) {
this.value = value;
this.children = [];
}
addChild(child) {
if (!this._checkCircular(child)) {
this.children.push(child);
}
}
_checkCircular(node) {
const visited = new WeakSet();
function check(current) {
if (visited.has(current)) return true;
visited.add(current);
for (let child of current.children) {
if (check(child)) return true;
}
return false;
}
return check(node);
}
}
实战应用案例
案例1:事件处理器管理
javascript
class EventManager {
constructor() {
this.handlers = new Set();
}
addHandler(handler) {
this.handlers.add(handler);
}
removeHandler(handler) {
this.handlers.delete(handler);
}
emit(event) {
this.handlers.forEach(handler => {
try {
handler(event);
} catch (error) {
console.error("Handler error:", error);
}
});
}
clear() {
this.handlers.clear();
}
}
案例2:投票系统防重复
javascript
class VotingSystem {
constructor() {
this.votes = new Map(); // 候选人 -> 票数
this.voters = new Set(); // 已投票用户ID
}
vote(voterId, candidate) {
// 检查是否已投票
if (this.voters.has(voterId)) {
throw new Error("每个用户只能投票一次");
}
// 记录投票
this.voters.add(voterId);
this.votes.set(candidate, (this.votes.get(candidate) || 0) + 1);
console.log(`用户 ${voterId} 投票给 ${candidate}`);
}
getResults() {
return Object.fromEntries(this.votes);
}
}
三、TypedArray 与 ArrayBuffer:高性能二进制数据处理
背景与设计动机
JavaScript 数值计算瓶颈:
javascript
// 传统数组的数值计算问题
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
// 问题:
// 1. 每个元素都是对象,内存开销大
// 2. 动态类型,无法优化
// 3. 无法直接与二进制 API 交互
TypedArray 解决方案:
javascript
// 创建 TypedArray
const intArray = new Int32Array([1, 2, 3, 4, 5]);
const doubled = intArray.map(n => n * 2);
// 优势:
// 1. 连续内存分配
// 2. 固定类型,可预测性能
// 3. 直接二进制操作
核心类型与 API
各种 TypedArray 类型:
javascript
// 不同数据类型的 TypedArray
const int8 = new Int8Array(10); // 8位有符号整数
const uint8 = new Uint8Array(10); // 8位无符号整数
const int16 = new Int16Array(10); // 16位有符号整数
const uint16 = new Uint16Array(10); // 16位无符号整数
const int32 = new Int32Array(10); // 32位有符号整数
const uint32 = new Uint32Array(10); // 32位无符号整数
const float32 = new Float32Array(10); // 32位浮点数
const float64 = new Float64Array(10); // 64位浮点数
// 特殊类型
const uint8Clamped = new Uint8ClampedArray(10); // 0-255 钳制值
基础操作与方法:
javascript
// 创建与初始化
const buffer = new ArrayBuffer(16); // 16字节缓冲区
const int32View = new Int32Array(buffer);
// 数据操作
int32View[0] = 42;
int32View[1] = 128;
console.log(int32View.length); // 4 (16字节 / 4字节每元素)
// 类数组方法
int32View.forEach((value, index) => {
console.log(`Index ${index}: ${value}`);
});
const squared = int32View.map(x => x * x);
const filtered = int32View.filter(x => x > 50);
// 子数组操作
const subarray = int32View.subarray(1, 3);
ArrayBuffer 与 DataView
ArrayBuffer 基础:
javascript
// ArrayBuffer 创建与使用
const buffer = new ArrayBuffer(16); // 16字节
console.log(buffer.byteLength); // 16
// 多个视图共享同一缓冲区
const int8View = new Int8Array(buffer);
const int16View = new Int16Array(buffer);
int8View[0] = 0x01;
int8View[1] = 0x02;
console.log(int16View[0]); // 0x0201 (小端字节序)
DataView 精确控制:
javascript
// DataView 用于精确字节控制
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
// 设置不同字节位置的值
view.setInt8(0, 127); // 第0字节
view.setFloat32(4, Math.PI); // 第4-7字节
view.setBigInt64(8, 123n); // 第8-15字节
// 读取时指定字节序
const intValue = view.getInt32(0, true); // 小端序
const floatValue = view.getFloat32(4, false); // 大端序
Mermaid 图示:TypedArray 内存布局
Int32Array[0]] B --> D[字节 4-7
Int32Array[1]] B --> E[字节 8-11
Int32Array[2]] B --> F[字节 12-15
Int32Array[3]] G[多视图共享] --> H[Int8Array: 16个元素] G --> I[Int16Array: 8个元素] G --> J[Int32Array: 4个元素] G --> K[Float64Array: 2个元素] L[DataView] --> M[精确字节控制] L --> N[字节序指定] L --> O[混合数据类型]
性能优化实战
数值计算优化:
javascript
// 矩阵运算示例
class Matrix {
constructor(rows, cols) {
this.rows = rows;
this.cols = cols;
this.data = new Float64Array(rows * cols);
}
get(row, col) {
return this.data[row * this.cols + col];
}
set(row, col, value) {
this.data[row * this.cols + col] = value;
}
// 矩阵乘法 - 优化版本
multiply(other) {
if (this.cols !== other.rows) {
throw new Error("矩阵维度不匹配");
}
const result = new Matrix(this.rows, other.cols);
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < other.cols; j++) {
let sum = 0;
for (let k = 0; k < this.cols; k++) {
sum += this.get(i, k) * other.get(k, j);
}
result.set(i, j, sum);
}
}
return result;
}
}
图像数据处理:
javascript
// 图像像素处理
class ImageProcessor {
constructor(width, height) {
this.width = width;
this.height = height;
this.pixels = new Uint8ClampedArray(width * height * 4); // RGBA
}
// 转换为灰度图
toGrayscale() {
for (let i = 0; i < this.pixels.length; i += 4) {
const r = this.pixels[i];
const g = this.pixels[i + 1];
const b = this.pixels[i + 2];
// 灰度公式
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
this.pixels[i] = gray; // R
this.pixels[i + 1] = gray; // G
this.pixels[i + 2] = gray; // B
// Alpha 保持不变
}
}
// 亮度调整
adjustBrightness(factor) {
for (let i = 0; i < this.pixels.length; i += 4) {
this.pixels[i] = Math.min(255, this.pixels[i] * factor); // R
this.pixels[i + 1] = Math.min(255, this.pixels[i + 1] * factor); // G
this.pixels[i + 2] = Math.min(255, this.pixels[i + 2] * factor); // B
}
}
}
四、SharedArrayBuffer 与 Atomics:多线程并发编程
背景与并发挑战
JavaScript 单线程限制:
javascript
// 传统 JS 无法真正并行计算
function heavyComputation() {
let sum = 0;
for (let i = 0; i < 1e9; i++) {
sum += i;
}
return sum;
}
// 这会阻塞主线程
console.time("单线程计算");
const result = heavyComputation();
console.timeEnd("单线程计算");
Web Worker 与共享内存:
javascript
// 主线程
const worker = new Worker("worker.js");
const sharedBuffer = new SharedArrayBuffer(1024);
const sharedArray = new Int32Array(sharedBuffer);
// 与 Worker 共享内存
worker.postMessage({ buffer: sharedBuffer });
// Worker 线程 (worker.js)
self.onmessage = function(event) {
const sharedArray = new Int32Array(event.data.buffer);
// 可以直接操作共享内存
for (let i = 0; i < sharedArray.length; i++) {
Atomics.add(sharedArray, i, 1);
}
};
Atomics 原子操作
数据竞争问题:
javascript
// 非原子操作的数据竞争
const sharedBuffer = new SharedArrayBuffer(4);
const sharedArray = new Int32Array(sharedBuffer);
// 两个线程同时执行以下操作可能出错
sharedArray[0] = sharedArray[0] + 1;
// 使用 Atomics 解决
Atomics.add(sharedArray, 0, 1); // 原子操作
原子操作 API:
javascript
const sharedArray = new Int32Array(new SharedArrayBuffer(16));
// 基本原子操作
Atomics.store(sharedArray, 0, 42); // 原子存储
const value = Atomics.load(sharedArray, 0); // 原子加载
// 算术运算
Atomics.add(sharedArray, 0, 5); // 原子加法
Atomics.sub(sharedArray, 0, 3); // 原子减法
// 位运算
Atomics.and(sharedArray, 0, 0xF); // 原子与
Atomics.or(sharedArray, 0, 0x1); // 原子或
Atomics.xor(sharedArray, 0, 0xFF); // 原子异或
// 比较交换 (CAS)
const oldValue = Atomics.compareExchange(sharedArray, 0, 42, 100);
同步原语实现
互斥锁 (Mutex):
javascript
class Mutex {
constructor(sharedBuffer, index = 0) {
this.lock = new Int32Array(sharedBuffer, index, 1);
}
acquire() {
while (true) {
// 尝试获取锁
if (Atomics.compareExchange(this.lock, 0, 0, 1) === 0) {
return;
}
// 等待并让出线程
Atomics.wait(this.lock, 0, 1);
}
}
release() {
// 释放锁并通知等待线程
Atomics.store(this.lock, 0, 0);
Atomics.notify(this.lock, 0, 1);
}
async execute(callback) {
this.acquire();
try {
return await callback();
} finally {
this.release();
}
}
}
信号量 (Semaphore):
javascript
class Semaphore {
constructor(sharedBuffer, index = 0, initial = 1) {
this.semaphore = new Int32Array(sharedBuffer, index, 1);
Atomics.store(this.semaphore, 0, initial);
}
async wait() {
while (true) {
const current = Atomics.load(this.semaphore, 0);
if (current > 0 && Atomics.compareExchange(this.semaphore, 0, current, current - 1) === current) {
return;
}
Atomics.wait(this.semaphore, 0, current);
}
}
post() {
const oldValue = Atomics.add(this.semaphore, 0, 1);
Atomics.notify(this.semaphore, 0, 1);
return oldValue + 1;
}
}
Mermaid 图示:多线程内存共享
实战应用案例
案例1:并行图像处理
javascript
// 主线程
class ParallelImageProcessor {
constructor(width, height, workerCount = 4) {
this.width = width;
this.height = height;
this.workerCount = workerCount;
this.workers = [];
// 创建共享内存
const pixelCount = width * height * 4;
this.sharedBuffer = new SharedArrayBuffer(pixelCount);
this.pixels = new Uint8ClampedArray(this.sharedBuffer);
this.setupWorkers();
}
setupWorkers() {
for (let i = 0; i < this.workerCount; i++) {
const worker = new Worker("image-worker.js");
worker.onmessage = (event) => {
this.completedWorkers++;
if (this.completedWorkers === this.workerCount) {
this.onComplete(this.pixels);
}
};
this.workers.push(worker);
}
}
processImage() {
this.completedWorkers = 0;
const rowsPerWorker = Math.ceil(this.height / this.workerCount);
this.workers.forEach((worker, index) => {
const startRow = index * rowsPerWorker;
const endRow = Math.min(startRow + rowsPerWorker, this.height);
worker.postMessage({
buffer: this.sharedBuffer,
width: this.width,
startRow,
endRow
});
});
}
}
案例2:科学计算并行化
javascript
// 并行矩阵运算
class ParallelMatrixMultiplier {
static multiply(a, b, workerCount = 4) {
return new Promise((resolve) => {
const rows = a.rows;
const cols = b.cols;
const resultBuffer = new SharedArrayBuffer(rows * cols * 4);
const result = new Float32Array(resultBuffer);
const workers = [];
let completed = 0;
const rowsPerWorker = Math.ceil(rows / workerCount);
for (let i = 0; i < workerCount; i++) {
const worker = new Worker("matrix-worker.js");
const startRow = i * rowsPerWorker;
const endRow = Math.min(startRow + rowsPerWorker, rows);
worker.onmessage = () => {
completed++;
if (completed === workerCount) {
workers.forEach(w => w.terminate());
resolve(result);
}
};
worker.postMessage({
a: a.data.buffer,
b: b.data.buffer,
result: resultBuffer,
aRows: a.rows,
aCols: a.cols,
bCols: b.cols,
startRow,
endRow
});
workers.push(worker);
}
});
}
}
五、性能对比与最佳实践
综合性能基准
javascript
class DataStructureBenchmark {
static runBenchmarks() {
const SIZE = 1000000;
// Map vs Object
console.time("Map creation");
const map = new Map();
for (let i = 0; i < SIZE; i++) {
map.set(`key${i}`, i);
}
console.timeEnd("Map creation");
console.time("Object creation");
const obj = {};
for (let i = 0; i < SIZE; i++) {
obj[`key${i}`] = i;
}
console.timeEnd("Object creation");
// Set vs Array 去重
const duplicates = Array.from({length: SIZE}, (_, i) => i % 1000);
console.time("Set deduplication");
const uniqueSet = [...new Set(duplicates)];
console.timeEnd("Set deduplication");
console.time("Array deduplication");
const uniqueArray = duplicates.filter((item, index) =>
duplicates.indexOf(item) === index
);
console.timeEnd("Array deduplication");
// TypedArray vs Array 数值计算
console.time("TypedArray math");
const typedArray = new Float64Array(SIZE);
for (let i = 0; i < SIZE; i++) {
typedArray[i] = Math.sin(i) * Math.cos(i);
}
console.timeEnd("TypedArray math");
console.time("Array math");
const normalArray = new Array(SIZE);
for (let i = 0; i < SIZE; i++) {
normalArray[i] = Math.sin(i) * Math.cos(i);
}
console.timeEnd("Array math");
}
}
DataStructureBenchmark.runBenchmarks();
最佳实践指南
数据结构选择决策表:
| 使用场景 | 推荐数据结构 | 理由 |
|---|---|---|
| 键值存储,键为字符串 | Object | 性能最优,语法简洁 |
| 任意类型键,需要顺序 | Map | 功能强大,顺序保证 |
| 对象关联元数据 | WeakMap | 自动内存管理 |
| 唯一值集合 | Set | 去重,快速查找 |
| 对象标记 | WeakSet | 自动垃圾回收 |
| 数值计算 | TypedArray | 高性能,内存连续 |
| 多线程数据共享 | SharedArrayBuffer | 真正并行处理 |
内存优化策略:
javascript
// 1. 及时清理引用
function processLargeData() {
const largeSet = new Set();
// 处理数据...
// 及时清理
largeSet.clear();
}
// 2. 使用对象池
class ObjectPool {
constructor(createFn) {
this.createFn = createFn;
this.pool = new Set();
}
acquire() {
if (this.pool.size > 0) {
const obj = this.pool.values().next().value;
this.pool.delete(obj);
return obj;
}
return this.createFn();
}
release(obj) {
this.pool.add(obj);
}
}
// 3. 预分配内存
class PreallocatedArray {
constructor(initialSize) {
this.buffer = new ArrayBuffer(initialSize * 8); // 假设存储 double
this.view = new Float64Array(this.buffer);
this.length = 0;
}
push(value) {
if (this.length >= this.view.length) {
this.#resize();
}
this.view[this.length++] = value;
}
#resize() {
const newBuffer = new ArrayBuffer(this.view.length * 2 * 8);
const newView = new Float64Array(newBuffer);
newView.set(this.view);
this.buffer = newBuffer;
this.view = newView;
}
}
Mermaid 图示:数据结构演进路线
原型链风险 Array : 顺序集合
类型松散 section ES6革命 Map : 任意类型键
顺序保证 Set : 唯一值集合
快速查找 WeakMap/WeakSet : 弱引用
自动GC section ES2017+ TypedArray : 类型化数组
高性能计算 SharedArrayBuffer : 共享内存
真正并行 Atomics : 原子操作
线程安全
六、未来演进与优化方向
语言特性发展
Records 和 Tuples 提案:
javascript
// 未来可能的不可变数据结构
#{
name: "Alice",
age: 25,
address: #{
city: "Beijing",
country: "China"
}
}
// 与 Map 的对比
const record = #{ x: 1, y: 2 };
const map = new Map([["x", 1], ["y", 2]]);
// Records 是不可变的,Map 是可变的
更多 TypedArray 类型:
javascript
// 未来可能增加的类型
// BigInt64Array, BigUint64Array - 已支持
// Float16Array - 正在标准化
// SIMD 类型 - 向量化运算
引擎优化趋势
JIT 编译优化:
- Map/Set 的内联缓存
- TypedArray 的向量化指令
- 共享内存的锁消除优化
内存管理改进:
- 更智能的预分配策略
- 压缩指针技术
- 分层内存管理
开发者建议
短期最佳实践:
- 根据场景选择合适的数据结构
- 注意内存管理和垃圾回收
- 利用类型化数组进行数值计算
- 在多线程场景谨慎使用共享内存
长期学习方向:
- 学习函数式编程与不可变数据
- 掌握并发编程模式
- 关注 WebAssembly 与 JavaScript 互操作
- 了解编译器优化原理