最稳妥的方式是用 Function.prototype.call 显式绑定到 Object.prototype 上执行。因为 Object.create(null) 创建的对象无 __proto__,自身可能重写方法,或原型链被污染,直接调用会出错;而 Object.prototype.方法名.call(目标对象, 参数...) 可绕过遮蔽与原型链问题,实现防御性编程。

当需要安全调用 Object.prototype 上的方法(比如 hasOwnProperty、toString、isPrototypeOf 等),又担心目标对象自身重写了这些方法或原型链被篡改时,最稳妥的方式是用 Function.prototype.call 显式绑定到 Object.prototype 上执行 —— 这叫“借用原生方法”。
为什么不能直接 obj.hasOwnProperty(key)?
因为:
立即学习“Java免费学习笔记(深入)”;
- obj 可能是
Object.create(null)创建的,没有__proto__,调用hasOwnProperty会报TypeError - obj 自身可能定义了同名属性(如
{ hasOwnProperty: false }),遮蔽了原型上的方法 - obj 的原型链可能被污染(比如有人改了
Object.prototype.hasOwnProperty = null)
正确借用 Object.prototype 方法的写法
统一格式:Object.prototype.方法名.call(目标对象, 参数...)
-
检查自有属性:
Object.prototype.hasOwnProperty.call(obj, 'key') -
安全获取类型字符串:
Object.prototype.toString.call(arr)→"[object Array]" -
判断是否为普通对象:
Object.prototype.toString.call(val) === '[object Object]' -
检测原型关系:
Object.prototype.isPrototypeOf.call(parent, child)
为什么不推荐用 obj.__proto__.hasOwnProperty?
因为:
立即学习“Java免费学习笔记(深入)”;
-
__proto__是非标准、已废弃的访问方式(虽仍被支持,但不推荐) -
obj.__proto__可能为null(如Object.create(null)),导致调用失败 -
Object.getPrototypeOf(obj)更规范,但依然无法绕过“方法被覆盖”的问题
实际开发中的典型场景
比如遍历对象属性并过滤掉继承属性:
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
console.log(key, obj[key]);
}
}
再比如判断一个值是不是数组(比 Array.isArray 更底层、兼容性更好):
function isArray(val) {
return Object.prototype.toString.call(val) === '[object Array]';
}
这种写法不依赖对象自身的原型链完整性,也不受属性遮蔽影响,是真正面向“防御性编程”的实践。


















