浅拷贝结合Object.keys的核心思路是获取对象自身可枚举属性名并遍历赋值到新对象,仅复制第一层属性,不处理嵌套结构;Object.keys只返回自身、可枚举、字符串键的属性,无法处理Symbol键、不可枚举属性及原型链属性。

浅拷贝结合 Object.keys 的核心思路是:**获取对象自身可枚举属性名,再遍历赋值到新对象上**。它只复制第一层属性,不处理嵌套对象或数组的深层结构。
用 Object.keys + for...of 实现浅拷贝
这是最直观的方式,适合理解原理:
function shallowCopy(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const keys = Object.keys(obj);
const copy = {};
for (const key of keys) {
copy[key] = obj[key];
}
return copy;
}
const original = { a: 1, b: { c: 2 }, d: [3, 4] };
const copied = shallowCopy(original);
copied.a = 99;
console.log(original.a); // 1(基础类型不受影响)
console.log(copied.b === original.b); // true(引用仍相同)
用 Object.keys + reduce 实现一行式浅拷贝
函数式风格,简洁但可读性略低:
const shallowCopy = obj =>
obj == null || typeof obj !== 'object'
? obj
: Object.keys(obj).reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
// 或更紧凑写法(ES6+):
const shallowCopy = obj =>
obj && typeof obj === 'object'
? Object.keys(obj).reduce((acc, k) => ((acc[k] = obj[k]), acc), {})
: obj;
注意 Object.keys 的局限性
Object.keys 只返回**自身、可枚举、字符串键**的属性,以下情况不会被拷贝:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- Symbol 类型的键(需用
Reflect.ownKeys或Object.getOwnPropertySymbols补充) - 不可枚举属性(如
Object.defineProperty设置的enumerable: false) - 原型链上的属性(
Object.keys不会遍历原型) - null 或原始值(需提前判断并返回原值)
更健壮的浅拷贝建议(兼容常见边界)
如果想覆盖 Symbol 键和不可枚举属性,可组合使用:
function robustShallowCopy(obj) {
if (obj == null || typeof obj !== 'object') return obj;
const keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
const copy = {};
for (const key of keys) {
const desc = Object.getOwnPropertyDescriptor(obj, key);
if (desc.enumerable || key instanceof Symbol) {
copy[key] = obj[key];
}
}
return copy;
}
不过日常开发中,Object.assign({}, obj) 或展开运算符 {...obj} 更常用且语义清晰;Object.keys 主要用于需要显式控制遍历逻辑的场景,比如过滤某些键、做类型检查或日志记录。

















