1 直接上解决方法:
将
obj.hasOwnProperty(prop)
改为Object.prototype.hasOwnProperty.call(obj, prop)
即可。
2 问题分析
以下来自大模型给出的解释,经过多轮问询后感觉回答的也挺详细,这里分享一下~
使用 Object.prototype.hasOwnProperty.call() 是一种安全的做法,因为它确保了即使对象的原型链被修改或篡改,我们调用的 hasOwnProperty 方法也是 Object.prototype 上的原始方法。下面是详细的说明和示例。
2.1 为什么需要确保?
JavaScript 中的 hasOwnProperty 方法用于检查一个对象是否拥有特定的自有属性,而不是继承自其原型链的属性。然而,如果对象的原型链被修改,直接调用 obj.hasOwnProperty(prop) 可能会调用到原型链上被篡改或覆盖的 hasOwnProperty 方法,导致不正确的行为。
2.2 如何确保?
Object.prototype.hasOwnProperty.call(obj, prop) 的调用方式确保了以下几点:
明确指定上下文:call 方法的第一个参数是 obj,这意味着 hasOwnProperty 方法被调用时,其内部的 this 值将被设置为 obj。这确保了 hasOwnProperty 方法是在检查 obj 的属性。
使用原始方法:由于 hasOwnProperty 是直接从 Object.prototype 上调用的,即使 obj 的原型链上的 hasOwnProperty 被覆盖或修改,这里使用的仍然是 Object.prototype 上的原始 hasOwnProperty 方法。
3 示例
假设我们有一个对象 user,我们想要检查它是否有一个名为 name 的属性:
var user = {
name: "Alice"
};
// 检查 user 对象是否有 name 属性
console.log(user.hasOwnProperty("name")); // 输出:true
如果 user 对象的原型链被篡改,例如:
user.__proto__ = {
hasOwnProperty: function() {
return false; // 总是返回 false
}
};
// 此时直接调用 user.hasOwnProperty("name") 将返回 false
console.log(user.hasOwnProperty("name")); // 输出:false
但是,如果我们使用 Object.prototype.hasOwnProperty.call():
// 即使原型链被篡改,仍然返回 true
console.log(Object.prototype.hasOwnProperty.call(user, "name")); // 输出:true
在这个例子中,即使 user 对象的原型链上的 hasOwnProperty 方法被覆盖为总是返回 false,使用 Object.prototype.hasOwnProperty.call(user, “name”) 仍然能够正确地检查 user 对象是否拥有 name 属性,因为它调用的是 Object.prototype 上的原始 hasOwnProperty 方法。