为什么在这里一般调用hasOwnProperty?

时间:2017-01-04 18:57:06

标签: javascript oop object

Axel Rauschmayer的 Speaking Javascript:深入的程序员指南中提到了以下功能:

function getDefiningObject(obj, propKey) {
    obj = Object(obj); // make sure it’s an object
    while (obj && !{}.hasOwnProperty.call(obj, propKey)) {
        obj = Object.getPrototypeOf(obj);
        // obj is null if we have reached the end
    }
    return obj;
}

正如作者所说,它的目的是“迭代”对象obj的属性链[并返回]具有自己属性的第一个对象propKey ,如果没有这样的对象,则为null

我理解这里的整体推理,但我不明白为什么{}.hasOwnProperty.call(obj, propKey)正在完成,而不仅仅是obj.hasOwnProperty(propKey)。有什么想法吗?

3 个答案:

答案 0 :(得分:7)

通常,开发人员会在内置类型上使用call来确保它们获得方法的正确本机行为,而不是某些被覆盖的行为。

这是一个我们真的不应该使用的保护措施,但因为对象在JavaScript中是如此具有可塑性,它保证我们得到我们想要的行为。

想象一下,如果某人(有意或无意地)创建了这样的对象:

function SuperObject(){
   this.foo = function(){
     // Something here
   };

   this.hasOwnProperty = 42;
}

然后,你来了(没有看到对象的实现)并写道:

var mySuperObject = new SuperObject();
console.log("Does 'mySuperObject' instance have its own 'foo' property? " +
            mySuperObject.hasOwnProperty("foo"));

你会得到这个:

function SuperObject(){
  this.foo = function(){
    // Something here
  };
    
  this.hasOwnProperty = 42;
}


var mySuperObject = new SuperObject();

// Safe way:
console.log("Does 'mySuperObject' instance have its own 'foo' property? " +
             {}.hasOwnProperty.call(mySuperObject, "foo"));

// Unsafe way (fails):
console.log("Does 'mySuperObject' instance have its own 'foo' property? " +
             mySuperObject.hasOwnProperty("foo"));

所以,我们得到这样的代码:

// This creates a new "fresh" (and unaltered) object with "object literal"
// syntax that you know doesn't override "hasOwnProperty"
{}.hasOwnProperty.call(obj, propKey)

// This performs the same task, but uses the native prototype object
// of the built-in Object type that we also know hasn't been altered:
Object.prototype.hasOwnProperty.call(obj, propKey) 

强制在原始hasOwnProperty的原型链上查找Object,同时:

obj.hasOwnProperty(propKey)

依赖于该属性在对象的特定实例(obj)上可用且正确。

其他常见的例子是Array类型:

// These work the same as the Object examples above, but just 
// do it for the Array type:
[].forEach.call(); // Array literal syntax
Array.prototype.forEach.call(); // Explicit array syntax

答案 1 :(得分:4)

如果对象的定义如下,public class News{ public int id {get;set;} public string Category {get;set;} public string Content {get;set;} } 会严重下降:

obj.hasOwnProperty
var obj = { hasOwnProperty: 123 };

使用var obj = Object.create(null); ,您可以从{}.hasOwnProperty获得对所需函数的引用,您不必担心它会在原型链中更近的地方被遮挡,或者不会继承自的对象Object.prototype

这是一个设计问题,因为Object.prototype应该是一个静态方法,但现在修复它已经太晚了。另一种解决方案是手动实施HasOwnProperty

hasOwnProperty

答案 2 :(得分:3)

如果您想对某个对象执行Object.prototype.hasOwnProperty,并尝试使用obj.hasOwnProperty(prop),则需要做出一些假设:

  • 该对象有一个名为"hasOwnProperty"的密钥。如果使用Object.create(null)创建对象,则很容易失败。
  • 该对象在obj.hasOwnProperty处有一个函数。如果对象具有已添加名为"hasOwnProperty"的键,则很容易失败。您可能认为这是一种罕见的情况,但将查询字符串等内容解析为对象并且查询字符串是用户提供的并不罕见。

使用Object.prototype.hasOwnProperty.call(obj, prop),您可以合理地保证在要传输的对象上调用您想要的方法。

出于实用目的,通常会看到以下内容:

function has(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}