shallowClone函数实现数组和对象的通用浅拷贝:先判断非对象类型直接返回,再用Array.isArray区分数组/对象并初始化对应空结构,最后用for...in+hasOwnProperty复制字符串键、Object.getOwnPropertySymbols复制Symbol键。

要实现一个同时支持数组和对象的通用浅拷贝函数,核心是判断输入类型、创建对应结构的新容器,再复制第一层可枚举属性(含字符串键和 Symbol 键),不递归处理嵌套引用。
支持数组和对象的基础逻辑
函数需先区分输入是否为 null 或基本类型——直接返回;再判断是否为数组或普通对象,分别初始化 [] 或 {};最后遍历并复制自有可枚举属性。
- 用
typeof obj !== 'object' || obj === null排除非对象类型 - 用
Array.isArray(obj)准确识别数组(比instanceof Array更可靠) - 用
for...in+hasOwnProperty复制字符串键,避免原型链污染 - 用
Object.getOwnPropertySymbols()获取并复制 Symbol 键(包括不可枚举的)
完整手写 shallowClone 函数
以下代码覆盖常见场景,包括 Symbol、稀疏数组兼容性、null/undefined 安全:
function shallowClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
const result = Array.isArray(obj) ? [] : {};
// 复制字符串键
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
result[key] = obj[key];
}
}
// 复制 Symbol 键
const symbols = Object.getOwnPropertySymbols(obj);
for (const sym of symbols) {
result[sym] = obj[sym];
}
return result;
}
为什么不用 Object.assign 或展开运算符?
它们虽简洁,但有明显局限:
-
Object.assign({}, obj)不复制 Symbol 键,也不保留原型链(如继承自某个构造函数) -
{...obj}对null或undefined报错,且无法处理类数组或带 getter 的对象 - 两者都不支持不可枚举属性(如
Object.defineProperty设置的enumerable: false属性)
实际使用注意点
浅拷贝只解决第一层赋值问题,对嵌套对象/数组无效。例如:
const source = { a: 1, b: [2, 3], c: { d: 4 } };
const cloned = shallowClone(source);
cloned.b.push(5); // source.b 也会变成 [2, 3, 5]
cloned.c.d = 99; // source.c.d 同样变为 99
若需隔离深层修改,必须配合深拷贝或业务层约定数据不可变。


















