JavaScript 中可通过实现 Symbol.iterator 接口使自定义图支持 for...of 遍历,内部用栈模拟 DFS(逆序压邻接点、Set 防环),返回标准迭代器;亦可提供 dfsIterator(startNode) 方法以支持指定起点等灵活策略。

JavaScript 中可以通过实现 Symbol.iterator 接口,让自定义图结构支持原生 for...of 遍历,并在迭代器内部封装深度优先遍历(DFS)逻辑。关键不是“暴露 DFS 过程”,而是“把 DFS 的逐节点产出行为包装成标准迭代器”。
图结构需支持可迭代接口
先定义一个基础图类,内部用邻接表存储节点关系,并返回一个符合 Iterator 协议的对象:
- 迭代器对象必须有
next()方法,返回{ value, done } -
next()内部用栈模拟递归 DFS:压入起始节点 → 每次弹出一个 → 访问它 → 将未访问的邻接节点逆序压栈(保证左子树/第一个邻接点先被处理) - 用 Set 记录已访问节点,避免环导致死循环
实现一个可迭代的 Graph 类
示例代码(不依赖外部库,纯原生 JS):
class Graph {
constructor() {
this.adj = new Map(); // Map<node array>>
}
<p>addEdge(from, to) {
if (!this.adj.has(from)) this.adj.set(from, []);
this.adj.get(from).push(to);
}</p>
<p>*[Symbol.iterator]() {
const nodes = Array.from(this.adj.keys());
if (nodes.length === 0) return;</p>
<pre class="brush:php;toolbar:false;">const visited = new Set();
const stack = [nodes[0]]; // 从第一个节点开始(也可接受起点参数)
while (stack.length > 0) {
const node = stack.pop();
if (visited.has(node)) continue;
visited.add(node);
yield node;
// 逆序压栈:保证邻接表中靠前的节点先被访问(DFS 左优先)
const neighbors = this.adj.get(node) || [];
for (let i = neighbors.length - 1; i >= 0; i--) {
if (!visited.has(neighbors[i])) {
stack.push(neighbors[i]);
}
}
}
} }
配合 for...of 和扩展运算符使用
一旦实现了 [Symbol.iterator],就能自然融入语言生态:
for (const node of myGraph) { console.log(node); }const dfsOrder = [...myGraph];-
Array.from(myGraph)或new Set(myGraph)
所有这些操作背后,都按 DFS 顺序逐个产出节点,无需手动调用递归函数或维护栈状态。
支持指定起点或多种遍历策略
若需更灵活控制(如从特定节点开始、或切换 BFS),可不直接实现 [Symbol.iterator],而提供显式方法返回迭代器:
-
dfsIterator(startNode)返回一个独立迭代器,内部仍用栈 + visited - 类本身保持不可迭代,避免语义歧义(图没有唯一自然遍历顺序)
- 这样既能复用 Iterator 协议,又保留算法参数化能力
例如:for (const n of graph.dfsIterator('A')) { ... }
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











