为什么使用Object.prototype.hasOwnProperty.call(myObj,prop)而不是myObj.hasOwnProperty(prop)?

如果我理解正确,JavaScript中的每个对象都继承自对象原型,这意味着JavaScript中的每个对象都可以通过其原型链访问hasOwnProperty函数。

在阅读 RequireJS 的源代码时,我偶然发现了这个函数:

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwn是对 的引用。将此函数编写为Object.prototype.hasOwnProperty

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

既然我们这样做了,我们为什么要定义这个函数呢?这是否只是一个快捷方式和属性访问的本地缓存的问题,以获得(轻微的)性能提升,或者我是否错过了任何可能在没有此方法的对象上使用 hasOwnProperty 的情况?


答案 1

[我的例子之间]有什么实际区别吗?

用户可能使用 创建了一个 JavaScript 对象,该对象将具有链,因此在其上不可用。由于这个原因,使用第二种形式将无法正常工作。Object.create(null)null[[Prototype]]hasOwnProperty()

这也是一个更安全的参考(也更短)。Object.prototype.hasOwnProperty()

你可以想象有人可能已经做了...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

如果它像第二个示例一样实现,这将失败(它将直接在对象上找到该方法并调用该方法,而不是被委托给)。hasProp(someObject)Object.prototype.hasOwnProperty

但是不太可能有人会覆盖引用。Object.prototype.hasOwnProperty

既然我们这样做了,我们为什么要定义这个函数呢?

见上文。

这是否只是一个快捷方式和属性访问的本地缓存的问题,以获得(轻微的)性能提升...

从理论上讲,它可能会使它更快,因为链条不必遵循,但我怀疑这可以忽略不计,而不是实现的原因。[[Prototype]]

...或者我是否遗漏了任何可能用于没有此方法的对象的情况?hasOwnProperty

hasOwnProperty()存在于 上,但可以被覆盖。每个原生JavaScript对象(但主机对象不能保证遵循这一点,请参阅RobG的深入解释)之前在链上的最后一个对象(当然,返回的对象除外)。Object.prototypeObject.prototypenullObject.create(null)


答案 2

如果我理解正确,JavaScript中的每个对象都继承自对象原型。

它可能看起来像是分裂头发,但是JavaScript(ECMAScript实现的通用术语)和ECMAScript(用于JavaScript实现的语言)之间存在差异。ECMAScript 定义了继承方案,而不是 JavaScript,因此只有本机 ECMAScript 对象需要实现该继承方案。

一个正在运行的 JavaScript 程序至少包含内置的 ECMAScript 对象(Object、Function、Number 等)和一些本机对象(例如函数)。它还可能具有一些宿主对象(例如浏览器中的 DOM 对象或其他宿主环境中的其他对象)。

虽然内置对象和本机对象必须实现 ECMA-262 中定义的继承方案,但主机对象则不然。因此,并非 JavaScript 环境中的所有对象都必须Object.prototype 继承。例如,Internet Explorer 中作为 ActiveX 对象实现的主机对象如果被视为本机对象,则会引发错误(因此,为什么 try..catch 用于初始化 Microsoft XMLHttpRequest 对象)。某些 DOM 对象(如 Internet Explorer 中 quirks 模式下的 NodeLists)如果传递给 Array 方法将引发错误,Internet Explorer 8 及更低版本中的 DOM 对象没有类似 ECMAScript 的继承方案,依此类推。

因此,不应假定 JavaScript 环境中的所有对象都继承自 Object.prototype。

这意味着JavaScript中的每个对象都可以通过其原型链访问hastOwnProperty函数。

至少对于 Internet Explorer 中处于 quirks 模式(以及 Internet Explorer 8 及更低版本)的某些主机对象而言,情况并非如此。

鉴于上述情况,值得思考的是,为什么一个对象可能有自己的 hasOwnProperty 方法,以及调用其他 hasOwnProperty 方法而不是在没有首先测试这是否是一个好主意的情况下可取的。

我怀疑使用的原因是,在某些浏览器中,宿主对象没有hasOwnProperty方法,使用调用和内置方法是一种替代方法。但是,由于上述原因,这样做通常似乎不是一个好主意。Object.prototype.hasOwnProperty.call

在涉及主机对象的情况下,in 运算符通常可用于测试属性,例如

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in Internet Explorer 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

另一种选择(在Internet Explorer 6和其他版本中测试):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

这样,您只需专门调用内置的 hasOwnProperty,而对象没有它(继承或以其他方式)。

但是,如果一个对象没有方法,那么使用in运算符可能同样适合,因为该对象可能没有继承方案,并且所有属性都在对象上(这只是一个假设),例如in运算符是测试DOM对象支持属性的常见(并且看似成功的)方法。hasOwnProperty