如何让递归函数在第n层停止?解决mousewheel事件序列化栈溢出问题
解决mousewheel事件序列化时的Maximum call stack size exceeded错误
问题背景
我尝试用下面的cloneAsObject函数序列化mousewheel事件对象,这个函数在其他场景下运行都正常,但处理mousewheel事件时却抛出了Maximum call stack size exceeded错误。想请教怎么修改这个函数,让它只返回第n层以内的属性和方法?
原函数代码:
function cloneAsObject(obj) { if (obj === null || !(obj instanceof Object)) { return obj; } var temp = (obj instanceof Array) ? [] : {}; for (var key in obj) { temp[key] = cloneAsObject(obj[key]); } return temp; }
问题原因
mousewheel事件对象内部存在循环引用(比如某个属性间接或直接引用了事件对象本身),你的递归函数会不断在这些引用之间循环调用,最终耗尽调用栈,抛出栈溢出错误。
解决方案:添加递归层级限制
我们可以给函数增加一个maxDepth参数,用来控制递归的深度,当达到指定层级后就不再深入遍历,直接返回当前值。这样既能避免栈溢出,也能满足“只保留第n层以内属性方法”的需求。
基础版修改
function cloneAsObject(obj, maxDepth = 2) { // 非对象、null,或者已达到最大深度,直接返回当前值 if (obj === null || !(obj instanceof Object) || maxDepth <= 0) { return obj; } var temp = (obj instanceof Array) ? [] : {}; for (var key in obj) { // 递归时层级减1 temp[key] = cloneAsObject(obj[key], maxDepth - 1); } return temp; }
使用时,你可以根据需要传入自定义的层级,比如只保留3层以内的属性:
const clonedEvent = cloneAsObject(mousewheelEvent, 3);
进阶版:同时处理循环引用
如果你的使用场景中,即使在指定层级内也可能存在循环引用,可以额外增加一个visited集合来记录已经处理过的对象,避免重复递归:
function cloneAsObject(obj, maxDepth = 2, visited = new WeakMap()) { if (obj === null || !(obj instanceof Object) || maxDepth <= 0) { return obj; } // 如果已经处理过这个对象,直接返回之前克隆的结果 if (visited.has(obj)) { return visited.get(obj); } var temp = (obj instanceof Array) ? [] : {}; // 记录当前对象已经被处理 visited.set(obj, temp); for (var key in obj) { temp[key] = cloneAsObject(obj[key], maxDepth - 1, visited); } return temp; }
这个版本不仅限制了递归深度,还能妥善处理循环引用的情况,避免同一对象被反复克隆导致的栈溢出或冗余数据。
内容的提问来源于stack exchange,提问作者user736893
相关产品推荐
相关产品推荐

