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

时间:2012-08-18 10:09:01

标签: javascript requirejs prototypal-inheritance hasownproperty

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

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

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

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

有什么实际区别
function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

既然我们在这,我们为什么要定义这个功能呢?这只是关于(轻微)性能提升的属性访问的快捷方式和本地缓存的问题,还是我错过了任何可能在没有此方法的对象上使用hasOwnProperty的情况?

4 个答案:

答案 0 :(得分:84)

  

我的例子之间是否存在实际差异?

用户可能拥有使用Object.create(null)创建的JavaScript对象,该对象将具有null [[Prototype]]链,因此不会有hasOwnProperty()。因此,使用您的第二个表单将无法正常工作。

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

你可以想象某人可能已经做过......

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

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

但不太可能有人会覆盖[[Prototype]]引用。

  

既然我们在这,我们为什么要定义这个功能呢?

见上文。

  是的吗?   只是一个快捷方式和本地缓存属性访问的问题   (轻微)业绩增长......

理论上它可能会更快,因为不必遵循hasOwnProperty链,但我怀疑这可以忽略不计,实施的原因就是为什么。

  

......或者我错过了任何案例   hasOwnProperty()可能用于没有此方法的对象?

Object.prototype上存在

Object.prototype,但可以覆盖。每个本机JavaScript对象(但主机对象不保证遵循此目的,see RobG's in-depth explanation)将null作为Object.create(null)之前链上的最后一个对象(当然除了{返回的对象之外) {1}})。

答案 1 :(得分:12)

  

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

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

正在运行的javascript程序至少包含内置的ECMAScript对象(对象,函数,数字等)以及可能的一些本机对象(例如函数)。它也可能有一些主机对象(例如浏览器中的DOM对象或其他主机环境中的其他对象)。

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

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

  

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

在怪癖模式(至少IE 8及更低版本)IE中,某些主机对象的情况并非如此。

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

修改

我怀疑使用Object.prototype.hasOwnProperty.call的原因是在某些浏览器中,主机对象没有 hasOwnProperty 方法,使用调用和内置-in方法是另一种选择。但是,出于上述原因,这样做通常不是一个好主意。

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

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

// false in most browsers, throws an error in IE 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');

替代方案(在IE6及其他方面测试):

function ownProp(o, prop) {

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

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

这样你只能专门调用内置的 hasOwnProperty ,而对象没有它(继承或其他)。

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

答案 2 :(得分:5)

  

JavaScript不保护属性名称 hasOwnProperty

如果存在对象可能具有此名称的属性的可能性,则必须使用外部hasOwnProperty来获得正确的结果:

您可以将以下代码段复制粘贴到浏览器控制台以更好地理解

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

始终返回false

foo.hasOwnProperty('bar'); // false

使用另一个Object的hasOwnProperty,并将 this 设置为foo

调用它
({}).hasOwnProperty.call(foo, 'bar'); // true

为此目的,也可以使用 Object 原型中的hasOwnProperty属性

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true

答案 3 :(得分:1)

现有答案中给出的信息都是现货。但是,使用:

('propertyName' in obj)

被提到几次。应该注意,只有当属性直接包含在被测对象上时,hasOwnProperty实现才会返回true。

in运算符也会检查原型链。

这意味着实例属性在传递给hasOwnProperty时将返回true,因为原型属性将返回false。

使用in运算符,instance和prototype属性都将返回true。