You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让递归函数在第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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:24:20