ES6类实现的撤销恢复管理器维护history和redoStack两个栈,支持push添加操作、undo撤销、redo恢复,自动清空重做栈并可限制最大步数。

用 ES6 类实现一个支持撤销(undo)和恢复(redo)的操作历史管理器,核心是维护两个栈:一个存已执行的操作(history),另一个存被撤销的操作(redoStack)。每次执行操作时推入 history;撤销时把最后一个操作弹出并压入 redoStack;恢复时则反向操作。
基础结构:定义类与关键属性
先声明类,初始化空数组作为历史栈和重做栈,并可选地限制最大步数防止内存膨胀:
-
history:存储已执行的“操作对象”,每个对象需含execute(正向执行)和undo(逆向回退)方法 -
redoStack:暂存被撤销的操作,供后续恢复使用 -
maxSteps(可选):限制history最大长度,超出时自动移除最早的操作
添加操作:push() 方法
接收一个操作对象,执行其 execute 方法后加入历史栈。若超出最大步数,则从开头裁剪:
push(operation) {
if (typeof operation.execute !== 'function' || typeof operation.undo !== 'function') {
throw new Error('Operation must have execute() and undo() methods');
}
operation.execute();
this.history.push(operation);
if (this.maxSteps && this.history.length > this.maxSteps) {
this.history.shift(); // 移除最老的操作
}
this.redoStack = []; // 新操作后清空 redo 栈(标准行为)
}
撤销与恢复:undo() 和 redo() 方法
撤销时检查历史栈是否为空;恢复时检查重做栈是否为空。注意:撤销后操作对象仍保留在 redoStack 中,以便多次恢复:
立即学习“Java免费学习笔记(深入)”;
-
undo():弹出
history末尾操作,调用其undo(),并压入redoStack -
redo():弹出
redoStack末尾操作,调用其execute(),并压回history - 两个方法都应返回布尔值表示是否成功(便于上层控制 UI 状态)
undo() {
if (this.history.length === 0) return false;
const op = this.history.pop();
op.undo();
this.redoStack.push(op);
return true;
}
redo() {
if (this.redoStack.length === 0) return false;
const op = this.redoStack.pop();
op.execute();
this.history.push(op);
return true;
}
实用操作对象示例
操作对象不依赖类,只需满足接口。例如文本编辑中的插入/删除:
const insertOp = {
text: 'hello',
position: 5,
execute() {
document.getElementById('editor').value =
document.getElementById('editor').value.slice(0, this.position) +
this.text +
document.getElementById('editor').value.slice(this.position);
},
undo() {
const el = document.getElementById('editor');
el.value = el.value.slice(0, this.position) + el.value.slice(this.position + this.text.length);
}
};
historyManager.push(insertOp); // 执行插入并记录
不复杂但容易忽略的是:操作必须是“纯”且可逆的——execute 和 undo 应只改变目标状态,不依赖外部临时变量;建议在构造操作对象时捕获必要快照(如当前值、光标位置等)。


















