先澄清一点:Reflect.ownKeys 本身并不负责“销毁”属性,它的职责是枚举对象自身的所有键——包括不可枚举和 Symbol 键。要真正删除属性,仍需借助 delete 运算符或将属性值赋为 undefined。而数组过滤在此充当“声明者”角色:通过白名单或黑名单定义敏感字段,再结合 Reflect.ownKeys 获取全部自有键,进行交集或排除,最终精准定位并清理目标属性。
下面一步步拆解这个流程。
明确敏感字段列表,通过数组定义白名单或黑名单
第一步,先把需要销毁的敏感属性名整理出来。例如常见的 "password"、"token"、"idCard",甚至可能包含 Symbol("session")。将这些名称存储为字符串或 Symbol 类型的数组。特别注意:Symbol 键必须使用原始的 Symbol 实例,不能通过 Symbol("xxx") 临时生成——因为每次调用都会创建新的 Symbol,无法匹配。
- 黑名单模式(销毁指定字段):
blacklist = ["password", "token", Symbol.for("auth")]; - 白名单模式(仅保留指定字段):
whitelist = ["id", "name", "email"];// 其余全部删除
用 Reflect.ownKeys 获取全部自有键,包含不可枚举与 Symbol 键
Reflect.ownKeys(obj) 返回一个数组,包含了对象所有自有属性的键。其顺序为:先按整数索引升序(对类数组对象也适用),然后按字符串键的创建顺序,最后是 Symbol 键。相较于 Object.keys() 或 Object.getOwnPropertyNames(),Reflect.ownKeys 更加全面——能够捕获通过 Object.defineProperty 设置的不可枚举属性,以及 Symbol 属性。
举个例子:
const user = { name: "Alice" };
Object.defineProperty(user, "password", { value: "123", enumerable: false });
user[Symbol("token")] = "abc";
Reflect.ownKeys(user); // ["name", "password", Symbol(token)]你看,password 虽不可枚举,Symbol("token") 虽是 Symbol,却无一遗漏。
遍历所有键并执行精准删除
获取全部键后,逐个判断是否属于敏感列表。若是,则通过 delete obj[key] 移除。这里有一个需要注意的地方:如果属性是不可配置的(configurable: false),delete 会静默失败(严格模式下会抛错)。此时,可以将属性值赋为 undefined 或 null,作为逻辑上的“销毁”。
- 黑名单方式(推荐):遍历
Reflect.ownKeys返回的键,判断每个 key 是否存在于 blacklist 中,若是则执行 delete。 - 白名单方式:先提取 whitelist 中实际存在的键,再遍历所有 ownKeys,不在 whitelist 中的都 delete。
- Symbol 匹配需确保引用一致:使用
Symbol.for("key")注册全局 Symbol,或直接复用定义时的 Symbol 常量。
封装成可复用的安全清理函数
最后,将上述逻辑封装成一个函数,支持传入目标对象和敏感字段数组,还可扩展配置项(如是否启用严格模式),以提高复用性和健壮性。
function scrubSensitive(obj, sensitiveKeys) {
if (typeof obj !== 'object' || obj === null) return obj;
const keys = Reflect.ownKeys(obj);
for (const key of keys) {
if (sensitiveKeys.some(s =>
(typeof s === 'symbol' && s === key) ||
(typeof s === 'string' && s === key)
)) {
try {
delete obj[key];
} catch (e) {
obj[key] = undefined; // fallback for non-configurable props
}
}
}
return obj;
}
// 使用示例
const data = { name: "Bob", password: "x", [Symbol("api")]: "secret" };
scrubSensitive(data, ["password", Symbol.for("api")]);如此一来,无论对象中包含多少不可枚举、Symbol 或不可配置的属性,都能精准按需清理,且不影响其他正常字段。再次强调:Reflect.ownKeys 只负责枚举属性,真正的“销毁”仍需通过 delete 或赋值为 undefined 实现,两者配合才能打出漂亮的组合拳。
