layui.extend 是浅拷贝,仅遍历赋值第一层属性,不递归处理嵌套对象;修改 target 的嵌套属性会同步影响 source,因其内部采用 for...in + hasOwnProperty 遍历,无 deep 参数支持。

layui.extend 是浅拷贝,不是深拷贝
layui.extend() 本质是属性遍历赋值,不递归处理嵌套对象,所以它只做浅拷贝。即使你传入多层嵌套对象,修改 target 中某个子对象的属性,源对象对应位置也会被改掉。
常见错误现象:layui.extend(target, source) 后修改 target.nested.name,结果 source.nested.name 也变了——这就是浅拷贝的典型表现。
- 它内部用的是类似
for...in+hasOwnProperty的遍历逻辑,不判断值类型是否为 object - 不支持
true参数控制深度,和 jQuery.extend 不同,layui.extend没有 deep 参数 - 如果你需要深拷贝,不能依赖
layui.extend,必须另选方案
layui.util.deepClone 是官方推荐的深拷贝方法
Layui 2.8+ 内置了 layui.util.deepClone,这是目前最稳妥、兼容性最好的选择。它能正确处理普通对象、数组、Date、RegExp 等常见类型,且不依赖 JSON 序列化(避免丢失 function、undefined、Symbol 等)。
使用场景:树节点状态备份、表格导出前数据预处理、表单重置时还原初始值等需要隔离引用的场合。
- 直接调用:
const cloned = layui.util.deepClone(originalObj) - 对
null、undefined、原始类型(string/number/boolean)安全返回原值 - 会跳过原型链上的属性,只拷贝自有可枚举属性
- 不处理循环引用,遇到会报错;如需支持循环引用,得自己加缓存 map
为什么不用 JSON.parse(JSON.stringify()) 做深拷贝?
虽然在 Layui 项目里常看到 JSON.parse(JSON.stringify(obj)) 被当深拷贝用,但它在实际业务中容易踩坑:
-
function、undefined、Symbol、BigInt全部丢失或报错 -
Date变成字符串,RegExp变成空对象{} - Map/Set/TypedArray 等无法序列化,结果为空或报错
- 如果对象含循环引用,直接抛
TypeError: Converting circular structure to JSON - 在表格导出图片场景中,有人用它深拷贝含 URL 的数据,结果 avatar 字段还在,但 Date 字段已失真——这会影响后续时间比对逻辑
layui.each 配合手动递归也能实现深拷贝,但不推荐
layui.each 是个通用遍历工具,可用于手写深拷贝逻辑,但属于“造轮子”行为,除非你有极特殊需求(比如只拷贝特定 key、跳过某些字段、定制类型处理),否则没必要。
示例片段(仅示意,非完整实现):
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const copy = Array.isArray(obj) ? [] : {};
layui.each(obj, function(key, val) {
copy[key] = typeof val === 'object' ? deepCopy(val) : val;
});
return copy;
}
注意点:
- 没处理 Date/RegExp/Map/Set 等内置对象,拷出来可能只是空对象
- 没判断循环引用,深层嵌套时可能栈溢出
- 性能不如
layui.util.deepClone,后者做了类型分支优化 - 维护成本高,Layui 升级后若
layui.each行为变化,你的深拷贝逻辑可能悄然失效
真正该花精力的地方,是确认哪些数据必须深拷贝、哪些可以共享引用——比如 tree 组件的 getChecked() 返回值已经是深拷贝,再套一层 deepClone 就是冗余操作。


















