Object.hasOwn 和 hasOwnProperty 有什么区别?
简化版
Object.hasOwn(obj, key) 用于判断某个属性是不是对象自身属性。它比 obj.hasOwnProperty(key) 更安全,因为对象可能没有原型,或者自己的属性名刚好覆盖了 hasOwnProperty。
它不会判断继承属性,也不会关心属性是否可枚举;只要是自有属性,就返回 true。
详细版
const obj = Object.create(null);
obj.name = "Ada";
// obj.hasOwnProperty("name"); // TypeError
Object.hasOwn(obj, "name"); // true
覆盖方法名的情况:
const user = {
hasOwnProperty: false,
id: 1
};
Object.hasOwn(user, "id"); // true
和 in 的区别:
const proto = { inherited: true };
const obj = Object.create(proto);
obj.own = true;
"inherited" in obj; // true
Object.hasOwn(obj, "inherited"); // false
完整版教学
一、属性判断先区分自身和继承
JavaScript 对象会沿原型链查找属性。
obj -> prototype -> prototype -> null
in 会看整条链,Object.hasOwn 只看对象自身。
面试问 hasOwn,本质是在问你有没有把“属性可访问”和“属性属于自己”分开。
二、Object.hasOwn 的基本用法
const obj = { a: 1 };
console.log(Object.hasOwn(obj, "a")); // true
console.log(Object.hasOwn(obj, "toString")); // false
它是静态方法,不依赖对象自身是否继承了某个方法。
三、为什么不直接用 obj.hasOwnProperty
普通对象一般可用:
({ a: 1 }).hasOwnProperty("a"); // true
但有两个风险。
第一,对象可能没有原型:
const dict = Object.create(null);
dict.a = 1;
第二,对象可能覆盖同名属性:
const obj = { hasOwnProperty: "not a function", a: 1 };
这时 Object.hasOwn(obj, "a") 更稳。
四、和 in 运算符的区别
const proto = { role: "admin" };
const user = Object.create(proto);
user.name = "Ada";
console.log("role" in user); // true
console.log(Object.hasOwn(user, "role")); // false
in 适合判断属性能否访问到,Object.hasOwn 适合判断是否为对象自己的数据。
五、不可枚举属性也算自有属性
const obj = {};
Object.defineProperty(obj, "hidden", {
value: 1,
enumerable: false
});
Object.keys(obj); // []
Object.hasOwn(obj, "hidden"); // true
自有和可枚举是两个维度,不要混在一起。
| 维度 | 判断方式 |
|---|---|
| 是否可访问 | key in obj |
| 是否自有 | Object.hasOwn(obj, key) |
| 是否可枚举 | propertyIsEnumerable 或遍历 API |
六、适合处理字典对象和外部输入
处理接口返回、配置对象、字典表时,属性名可能不可控。
function getOwnValue(obj, key) {
if (Object.hasOwn(obj, key)) {
return obj[key];
}
return undefined;
}
这比直接调用 obj.hasOwnProperty 更少假设。
七、常见误区与追问
- 误区:
in和Object.hasOwn等价。in会检查原型链,hasOwn只检查自身。 - 误区:不可枚举属性不是自有属性。 可枚举和自有是不同维度。
- 误区:所有对象都能调用 hasOwnProperty。
Object.create(null)创建的对象没有这个方法。 - 误区:对象自己的 hasOwnProperty 一定是函数。 它可能被业务字段覆盖。
- 追问:为什么处理外部输入时 hasOwn 更安全? 因为它不依赖对象原型和对象上的同名方法。
- 追问:Object.hasOwn 会不会触发 getter? 判断属性存在性本身不需要读取属性值。
八、加强记忆
记忆对比:
key in obj -> own or inherited
Object.hasOwn(obj,key) -> own only
Object.keys(obj) -> own enumerable string keys
回答时先讲原型链,再给 Object.create(null) 和同名覆盖两个例子,最后补“自有不等于可枚举”,这题就稳了。