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

IT技术 javascript requirejs prototypal-inheritance hasownproperty
2021-01-21 23:21:27

如果我理解正确的话,JavaScript 中的每个对象都继承自 Object 原型,这意味着 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 的任何情况?

6个回答

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

用户可能有一个用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,但可以被覆盖。每个原生 JavaScript 对象(但不保证宿主对象都遵循这一点,请参阅 RobG 的深入解释Object.prototype作为其之前链上的最后一个对象null(当然由 返回的对象除外Object.create(null))。

如果经常使用 ES6 快捷方式。 const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)
2021-03-14 23:21:27
@Periback 真的吗?我很确定它确实支持它。
2021-03-24 23:21:27
你的逻辑可能是正确的,但我认为你很善良。如果 require.js 的作者认为hasOwnProperty可能已被覆盖(这是极不可能的),那么他们应该以这种方式调用所有内置方法(也许他们确实这样做了)。
2021-04-11 23:21:27

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

这似乎是一刀切,但JavaScript(ECMAScript 实现的通用术语)和ECMAScript(用于 JavaScript 实现的语言之间是有区别的定义继承方案的是 ECMAScript,而不是 JavaScript,因此只有本机 ECMAScript 对象需要实现该继承方案。

一个正在运行的 JavaScript 程序至少由内置的 ECMAScript 对象(对象、函数、数字等)和一些本地对象(例如函数)组成。它也可能有一些宿主对象(例如浏览器中的 DOM 对象,或其他宿主环境中的其他对象)。

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

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

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

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

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

我怀疑使用的原因Object.prototype.hasOwnProperty.call是在某些浏览器中,宿主对象没有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

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

谢谢。Object.prototype.hasOwnProperty.call(o, 'bar') 在 FF 18.0 中不起作用(至少在我的情况下)。所以我决定使用 ('bar' in o) - 它有帮助。
2021-03-15 23:21:27
这是来自eslint.org/docs/rules/no-prototype-builtins 的一个有趣示例例如,网络服务器解析来自客户端的 JSON 输入并hasOwnProperty直接调用结果对象是不安全的,因为恶意客户端可以发送类似的 JSON 值{"hasOwnProperty": 1}并导致服务器崩溃。
2021-03-15 23:21:27
@Maxin不执行hasOwnProperty()查找,我怀疑您要查找的属性存在于原型链中。
2021-04-03 23:21:27
当然,但使用 JSON 模式测试或验证任何客户端提供的 JSON 以防止此类问题是明智的,即使您只关心数据质量。并且它不应该导致服务器崩溃。:-)
2021-04-03 23:21:27

JavaScript 不保护属性名hasOwnProperty

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

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

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

总是返回假

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

使用另一个对象的hasOwnProperty,并调用它这个集为foo

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

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

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
您在接受的答案中已经提出了这一点,除了有覆盖的hasOwnProperty回报true
2021-04-01 23:21:27

前两个答案(按日期)中给出的信息是正确的。但是,使用:

('propertyName' in obj)

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

in运营商将检查下来,通过原型链了。

这意味着实例属性在传递到hasOwnPropertywhere时将返回 true ,而原型属性将返回 false。

使用in运算符实例和原型属性都将返回 true。

它更简单:

let foo = Object.create(null);
if (foo.bar != null) {
    console.log('object foo contains bar property in any value and 
    type, except type undefined and null');
    // bar property can exist in object foo or any object of the prototype chain
}
请在您的回答中提供更多详细信息。正如目前所写,很难理解您的解决方案。
2021-03-27 23:21:27