Proxy 的 ownKeys 拦截器直接控制 Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols() 和 for...in 循环暴露的自有属性键列表,必须返回仅含字符串或 Symbol 的数组,否则抛错;需配合 has 和 get 拦截才能实现真正“隐藏属性”。

Proxy 的 ownKeys 拦截器能直接控制 Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols() 以及 for...in 循环所看到的“自有属性键列表”。它不改变属性是否存在或能否访问,而是决定哪些键被“暴露”出来。
ownKeys 必须返回一个数组,且元素只能是字符串或 Symbol
这是硬性要求。返回非数组、包含非法类型(如数字、null、undefined)会直接抛错。
- 合法返回值示例:
['a', 'b']、[Symbol('x'), 'y'] - 非法返回值示例:
null、{}、['a', 123]、['a', undefined]
拦截 Object.keys 时,ownKeys 返回的数组就是 keys 结果
Object.keys() 内部会调用目标对象的 [[OwnPropertyKeys]](即触发 ownKeys),再过滤掉非字符串、不可枚举的键。但注意:ownKeys 本身不负责过滤,它只提供原始键列表;Object.keys 会在其基础上进一步筛出可枚举的字符串键。
所以若想让某个字符串键不出现在 Object.keys() 中,最直接的方式是在 ownKeys 中不返回它。
立即学习“Java免费学习笔记(深入)”;
例如:
let target = { a: 1, b: 2, c: 3 };let proxy = new Proxy(target, {
ownKeys() { return ['a', 'b']; } // 不含 'c'
});
console.log(Object.keys(proxy)); // ['a', 'b']
配合 has / get / ownKeys 一起用,实现“隐藏属性”效果
仅靠 ownKeys 隐藏键名还不够——如果用户直接 proxy.c 访问,仍能读到值。要真正“隐藏”,需同步拦截 get 和 has:
-
ownKeys:不返回该键 → 它不会出现在Object.keys或for...in -
has:对这个键返回false→'c' in proxy为false -
get:对这个键返回undefined或抛错 →proxy.c无法正常取值
这样组合后,属性就像“不存在”一样,既不可见、也不可查、更不可读。
注意与 Reflect.ownKeys 的协作
推荐在 ownKeys 中调用 Reflect.ownKeys(target) 获取原始键,再做筛选。这能确保不遗漏继承来的不可枚举属性(如 constructor)、Symbol 键等,同时保持行为兼容。
例如只暴露以 _ 开头的私有属性:
return Reflect.ownKeys(target).filter(key =>
typeof key === 'string' && key.startsWith('_')
);
}


















