Object.keys()只返回对象自身可枚举的字符串键,不访问原型链;它绕开\_\_proto\_\_和Object.getPrototypeOf(),仅枚举own且enumerable: true的属性,故继承属性即使可访问也不被包含。

Object.keys() 本身不“使用”原型,它刻意绕开原型——这是它的设计原则。它只检查对象自身(own)的属性,并且只收集那些 enumerable: true 的字符串键,完全忽略从 [[Prototype]] 链上继承来的任何属性,无论是否可枚举。
为什么 Object.keys 不会遍历原型上的属性
它内部调用的是 JavaScript 引擎的“自有可枚举属性枚举”机制,等价于:
- 逐个检查该对象自身的属性(不向上查找)
- 跳过所有
enumerable: false的属性(比如通过Object.defineProperty设置的不可枚举属性) - 跳过所有
Symbol类型的键 - 不访问
obj.__proto__或Object.getPrototypeOf(obj)上的任何内容
原型链上的属性明明能访问,为什么 Object.keys 看不见
因为“能访问”和“属于该对象”是两回事。例如:
const parent = { x: 10 };
const child = Object.create(parent);
child.y = 20;
console.log(child.y); // 20 → 自身属性,可读
console.log(child.x); // 10 → 继承属性,可读
console.log(Object.keys(child)); // ['y'] → 只返回自身可枚举键
console.log(Object.keys(parent)); // ['x']
这里 child.x 是通过原型链动态查找到的,但 x 并不在 child 对象自身上,所以 Object.keys(child) 不会包含它。
立即学习“Java免费学习笔记(深入)”;
想同时拿到自身 + 原型链上的可枚举键?得手动处理
Object.keys 本身做不到,但你可以组合其他 API 实现类似效果:
- 用
Reflect.ownKeys()获取自身所有键(含不可枚举、Symbol) - 用
Object.getPrototypeOf(obj)向上遍历原型链 - 自己写一个递归函数,逐层调用
Object.keys()并去重合并
不过要注意:这种需求很少见,多数时候你真正需要的,恰恰就是 Object.keys() 提供的“干净、隔离、可预测”的自有属性列表——这正是它被广泛用于数据序列化、表单校验、状态快照等场景的原因。
常见误区提醒
别误以为“加了 prototype 就能被 Object.keys 看到”。比如:
function Person() {}
Person.prototype.sayHi = function() {};
const p = new Person();
Object.keys(p); // [] —— p 自身空空如也,sayHi 在原型上
即使你给 Person.prototype 添加了大量方法或属性,只要它们不在 p 实例自身上,Object.keys(p) 就永远返回空数组。


















