JS浅拷贝过滤敏感字段的核心是“不复制”而非“先复制再删”:推荐用解构剩余语法静态剔除固定字段,或白名单校验硬编码合法键并显式拦截__proto__等危险键,避免修改原对象、触发副作用及原型污染。

JS 浅拷贝时过滤敏感字段,核心是“不复制”而非“先复制再删”。直接用 Object.assign 或展开运算符全量拷贝再 delete,既破坏原对象(若误操作),又可能漏掉危险键(如 __proto__)、触发副作用或性能浪费。推荐从源头控制:只取白名单字段,或显式跳过黑名单字段。
用解构 + 剩余语法静态裁剪
适合已知要剔除的固定字段(如 token、password、createdAt):
- 写法简洁,语义清晰,生成新对象,不修改原数据
- 必须显式列出所有要跳过的键,未列出的才会进入剩余对象
- 仅处理自有可枚举属性,不触碰原型链、Symbol 键、
null/undefined值
示例:
const { token, password, ...safeUser } = user;→ safeUser 就是过滤后的浅拷贝,不含 token 和 password。
用白名单校验安全拷贝
适合对输入对象做可信度控制(如 API 请求体、表单提交),防止原型污染和非法字段注入:
- 白名单应硬编码,如
const USER_WHITELIST = ['id', 'username', 'email'] as const - 遍历白名单,逐个检查
source.hasOwnProperty(key)后赋值,不依赖Object.keys全量提取 - 必须额外拦截
__proto__、constructor、prototype等危险字符串,哪怕不在白名单中也禁止访问
示例逻辑:
const safe = {};USER_WHITELIST.forEach(key => {
if (key === '__proto__' || key === 'constructor') return;
if (user.hasOwnProperty(key)) safe[key] = user[key];
});
动态过滤多个字段(黑名单模式)
当需根据运行时配置剔除字段(如不同接口屏蔽不同字段),剩余语法无法满足,需组合 Object.entries 与 Object.fromEntries:
- 用
Set存储待剔除字段,提升查找效率 -
filter遍历时跳过黑名单中的 key,保留其余项 - 仍为浅拷贝,嵌套对象保持引用,不处理 Symbol 或不可枚举属性
示例函数:
const omit = (obj, keysToOmit) => {const blacklist = new Set(keysToOmit);
return Object.fromEntries(
Object.entries(obj).filter(([k]) => !blacklist.has(k))
);
};
const clean = omit(userData, ['token', 'internal_id']);
为什么不用 delete 或赋 undefined?
这两种方式都作用于原对象,违反“拷贝应隔离”的前提:
-
obj.token = undefined:字段仍在,Object.keys()仍可见,且下游用hasOwnProperty判定时会误认为存在 -
delete obj.token:虽真正移除,但修改了原始数据,若该对象被其他模块共享,将引发隐性 bug - 二者都无法防御
__proto__.polluted = true类型的原型链污染











