【问题标题】:Are there any cases when I should use the in operator instead of hasOwnProperty()?在任何情况下我应该使用 in 运算符而不是 hasOwnProperty()?
【发布时间】:2017-03-13 03:48:01
【问题描述】:

在 JavaScript 中,in 运算符检查对象是否具有指定的属性。但是,它不仅检查对象自身的属性,还检查原型链。因此,在某些情况下,它的行为可能不完全符合预期。

假设由于某种原因我们有一个对象someArrayMethods,其中包含(显然)一些数组方法作为键:

const someArrayMethods = {
  indexOf: true,
  map: true,
};

我们可以使用in 运算符检查该对象是否具有特定方法作为键:

console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false

如果我们尝试检查 toString 属性会怎样?

console.log('toString' in someArrayMethods); // true

惊喜!原来这个对象在原型链中有一个toString method,所以in操作符返回true,即使这个对象没有自己的toString属性。

这就是hasOwnProperty() 来救援的地方!它与in 运算符几乎相同,但有一个区别:它不检查原型链。我们可以重写我们之前的例子:

console.log(someArrayMethods.hasOwnProperty('toString'));  // false

现在它可以按预期工作了。不幸的是,hasOwnProperty() 在一种情况下也可能失败。如果我们有一个拥有自己属性hasOwnProperty 的对象呢?看这个例子:

const someObject = {
  hasOwnProperty() {
    return false;
  },
  theAnswer: 42,
};

// Does `someObject` has own property `theAnswer`?
console.log(someObject.hasOwnProperty('theAnswer')); // false
// Well, it seems it doesn't...

为了解决这个问题,我们可以直接从Object.prototype引用该方法,而不是使用someObject.hasOwnProperty:

const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true

这似乎是检查对象是否具有某些属性的最合理方法。尽管如此,在任何情况下in 运算符会很有用?我知道它可以用来检查某个类的实例是否有某种方法,但是在这种情况下,简单地检查该对象是否是该类的实例不是更好吗?


附带说明,另一种选择是将 Object.keys() 与 ECMAScript 2016 Array.prototype.includes() 一起使用:

console.log(Object.keys(someObject).includes('theAnswer')); // true

【问题讨论】:

  • 在大多数情况下,如果一个函数接受具有某些属性的东西 - 它不应该是它的业务在原型链中定义属性的位置,而是它只是可用的。这样您就可以将数据形状与实现细节分开。

标签: javascript object prototype hasownproperty ecmascript-2016


【解决方案1】:

in 是一个操作符,所以不能被劫持。您不必依赖没有更改或隐藏脚本Object、Object.prototype、Object.prototype.hasOwnProperty、Object.prototype.hasOwnProperty.call。

这是了解对象是否具有某些属性的快速方法。我的意思是,如果obj.foo 可以返回,例如"bar" 即使foo 属性是继承的,也有必要事先知道obj 是否具有foo 属性,无论是拥有还是继承。

当然,如果我们只有 HasOwnProperty,我们可以(通常)继续调用 [[GetPrototypeOf]] 直到链的末尾,并检查每个对象。但这对代码来说会很乏味,可能比原生 in 慢,并且在 ES5 之前是不可能的。

此外,还有一个根本区别。 in 运算符使用 [[HasProperty]] 内部方法,而 HasOwnProperty 使用 [[GetOwnProperty]]。对于非普通对象,迭代 [[GetOwnProperty]] 和 [[GetPrototypeOf]] 可能会产生与 [[HasProperty]] 不同的结果。

所以是的:当您想调用对象的内部 [[HasProperty]] 方法时,in 运算符很有用。事实上,除了Reflect.has,这是唯一正确的方法。

var p = new Proxy({}, {has: function() {
  console.log('Hooray!');
  return true;
}});
p.hasOwnProperty('foo'); // :(
'foo' in p; // Hooray! :)

【讨论】:

    【解决方案2】:

    你回答你自己的问题。 in 也适合在原型链中搜索。

    【讨论】:

    • 我正在寻找特定的用例,例如 amdouglas 的回答。
    【解决方案3】:

    用于加载 polyfill 的功能检测、使用现代 DOM API 的测试条件等。

    使用in 运算符非常适合评估您是否应该精确地加载/执行 JavaScript polyfill,因为它会检查原型链。

    例如:

    // this works wonderfully
    if (!('addEventListener' in window)) {
      // polyfill addEventListener
    }
    

    相比:

    // this doesn't work at all
    if (!window.hasOwnProperty('addEventListener')) {
      // polyfill addEventListener
    }
    

    因此the Polyfill.io service 使用它进行特征检测测试。

    【讨论】:

      猜你喜欢
      • 2011-05-31
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      • 2019-08-08
      相关资源
      最近更新 更多