在 javascript 中,判断属性来源主要依靠 hasownproperty() 方法、in 运算符以及 object.keys() 函数。这三者分别用于检测自有属性、遍历原型链上的所有可枚举属性以及仅获取自有属性的键名。

hasOwnProperty() 如何区分自有与继承属性
hasOwnProperty() 是 Object.prototype 上的一个方法,它返回一个布尔值,指示对象本身(非原型链)是否拥有指定的属性。这是判断属性来源最直接的方式。

function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello");
};
const p = new Person("Alice");
console.log(p.hasOwnProperty('name')); // true: 'name' 是自有属性
console.log(p.hasOwnProperty('sayHello')); // false: 'sayHello' 在原型链上
console.log(p.hasOwnProperty('toString')); // false: 'toString' 在 Object.prototype 上
运行上述代码,控制台将输出:
true
false
false
立即学习“Java免费学习笔记(深入)”;
需要注意的是,如果对象的某个自有属性名为 hasOwnProperty,它会覆盖原型上的该方法,导致调用失败。此时可以使用 Object.prototype.hasOwnProperty.call(obj, prop) 来安全调用。
in 运算符与 Object.keys() 的行为差异
in 运算符检查的是属性是否存在于对象或其原型链中,只要找到就返回 true。而 Object.keys() 则只返回对象自身可枚举属性的键名数组,完全忽略原型链上的属性。

const obj = { a: 1 };
obj.b = 2;
// 模拟原型链
const proto = { c: 3 };
Object.setPrototypeOf(obj, proto);
console.log('a' in obj); // true: 自有属性
console.log('b' in obj); // true: 自有属性
console.log('c' in obj); // true: 原型链上的属性
console.log('d' in obj); // false: 不存在
console.log(Object.keys(obj)); // ['a', 'b']: 仅自有属性
console.log(Object.getOwnPropertyNames(obj)); // ['a', 'b']
运行结果:true, true, true, false[ 'a', 'b' ][ 'a', 'b' ]
通过对比可以发现,in 会穿透原型链,而 Object.keys() 和 Object.getOwnPropertyNames() 只关注对象自身。如果需要判断属性是否“存在”且“属于当前对象”,应结合使用 in 和 hasOwnProperty()。
当自有属性遮蔽原型属性时如何处理
当对象拥有一个与原型链同名的自有属性时,该自有属性会“遮蔽”原型属性。此时 hasOwnProperty() 仍返回 true,因为属性确实存在于对象自身。这种行为在处理配置合并或类继承时非常关键。
function Config() {
this.theme = 'light';
}
Config.prototype.theme = 'dark';
const cfg = new Config();
console.log(cfg.theme); // 'light': 自有属性遮蔽了原型属性
console.log(cfg.hasOwnProperty('theme')); // true
// 删除自有属性后,访问回原型
delete cfg.theme;
console.log(cfg.theme); // 'dark': 现在访问到原型属性
预期输出:'light'true'dark'
这种遮蔽机制意味着 hasOwnProperty() 只能告诉你属性是否在对象实例上,而不能直接告诉你它是否覆盖了原型。如果需要获取原型上的原始值,可以使用 Object.getPrototypeOf(obj).property 或直接访问原型链上的定义。


















