【问题标题】:What is the appropriate / recommended way to use hasOwnProperty?使用 hasOwnProperty 的适当/推荐方式是什么?
【发布时间】:2017-05-27 00:32:09
【问题描述】:

假设对象可以包含自己的名为“hasOwnProperty”的属性:

> a={abc: 123};
{ abc: 123 }
> a.hasOwnProperty("abc");
true
> a['hasOwnProperty'] = 1;
1
> a.hasOwnProperty("abc");
TypeError: a.hasOwnProperty is not a function
...

如果您考虑 Object.keys()、Object.assign() 等,这可行,有点丑陋的界面。那么,有没有更好的方法?

> Object.hasOwnProperty.call(a, "abc");
true
> Object.hasOwnProperty.call(a, "hasOwnProperty");
true

为什么解决方案不应该是唯一推荐的方法?直接从一个对象中使用方法似乎是一个失败的秘诀,尤其是如果它包含外部数据(不受控制)

【问题讨论】:

标签: javascript


【解决方案1】:

使用 hasOwnProperty 的适当/推荐方式是作为过滤器,或者是确定对象是否……嗯,是否具有该属性的方法。只是他们在您的第二个命令中使用它的方式a.hasOwnProperty('abc')

通过用a['hasOwnProperty'] = 1 覆盖对象hasOwnProperty 属性,虽然它是安全有效的,但只是删除了对该对象使用hasOwnProperty 函数的能力。

我在这里错过了你真正的问题吗?您似乎已经从您的示例中知道了这一点。

'直接使用对象的方法似乎是失败的秘诀

你指的是这样的东西吗:

 > dog = {speak: function() {console.log('ruff! ruff!')}};
 > dog.speak(); // ruff! ruff!

因为它在许多方面都非常有用,您可以想象。

【讨论】:

  • 我指的是将数据(例如对文档进行标记)加载到对象中。该文档可能是关于 javascript 的,并且可能包含令牌“hasOwnProperty”。当然,使用带有方法的对象很强大,但这不是我的问题。
【解决方案2】:

如果您可以使用 ECMAScript 2015,您可以尝试Reflect.getOwnPropertyDescriptor。 如果它存在于对象上,则返回给定属性的属性描述符,否则返回未定义。

为了简化你可以创建这个函数:

var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;

var obj = new Object();
obj.prop = 'exists';

console.log('Using hasOwnProperty')
console.log('prop: ' + obj.hasOwnProperty('prop'));            
console.log('toString: ' + obj.hasOwnProperty('toString'));        
console.log('hasOwnProperty: ' + obj.hasOwnProperty('hasOwnProperty'));   

var hasOwnProp = (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop) !== undefined;

console.log('Using getOwnPropertyDescriptor')
console.log('prop: ' + hasOwnProp(obj, 'prop'));
console.log('toString: ' + hasOwnProp(obj, 'toString'));
console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));

obj['hasOwnProperty'] = 1;

console.log('hasOwnProperty: ' + hasOwnProp(obj, 'hasOwnProperty'));

【讨论】:

  • 感谢您指出Reflect.getOwnPropertyDescriptor()。哪方面比Object.hasOwnProperty.call(obj, prop)好?
【解决方案3】:

任何内置方法都可以在 JS 中被覆盖 - 通常认为最好的做法是尽可能避免覆盖任何本机方法。如果保留了原始功能,则没关系,因为它仍将按预期运行,如果再次正确覆盖,甚至可能进一步扩展。

由于这被认为是最佳做法,我建议重新映射键以避免覆盖它们。如果重新映射键不是一个选项,那么您可以通过本地引用/包装Object.hasOwnPropertyObject.prototype.hasOwnProperty 来让它感觉不那么混乱。在hasOwnProperty 的情况下,您可以实现一个迭代器(因为迭代可枚举的非继承属性是hasOwnProperty 的一种非常常见的用法)方法来降低其使用的可能性。仍然存在对您的对象不太熟悉的人尝试直接迭代的风险,所以我真的觉得键映射是更安全的选择,即使它确实会导致服务器端键和本地键之间的细微差别。

键映射可以像使用 hasOwnProperty_data 而不是 hasOwnProperty 的后缀一样简单,这意味着对象将按预期运行,并且您的 IDE 的自动完成功能可能仍然足够接近以知道属性代表什么。

映射函数可能如下所示:

function remapKeys(myObj){
    for(var key in myObj){
      if(Object.prototype.hasOwnProperty.call(myObj, key)){      
        if((key in Object) && Object[key] !== myObj[key]){ // Check key is present on Object and that it's different ie an overridden property
          myObj[key + "_data"] = myObj[key]; 
          delete myObj[key]; // Remove the key   
        } 
      }
    }
    return myObj; // Alters the object directly so no need to return but safer
}

// Test
var a = {};
a.hasOwnProperty = function(){ return 'overridden'; };
a.otherProp = 'test';
remapKeys(a);
console.log(a); // a { hasOwnProperty_data : function(){ return 'overridden';}, otherProp: 'test' } 
console.log(a.hasOwnProperty('otherProp')); // true

【讨论】:

  • 这似乎是为了避免覆盖内置方法而产生的大量开销(内存和代码)。我宁愿用Object.create(null)确保它没有任何方法@
  • 您只需要前 11 行,并且您只需在加载数据后运行一次。这样做的内存占用量将是最小的,它会在适当的位置修改对象而不克隆它等。我认为访问内置插件和避免混淆是一个很小的代价。我认为我的示例没有处理的唯一考虑是嵌套对象 - 将其重构为使用递归将处理这些。第二个是拥有“自定义映射”而不是仅仅附加一个后缀可能是有益的。使用空原型创建对象可能与覆盖内置函数一样令人困惑。
猜你喜欢
  • 2011-11-05
  • 2016-08-05
  • 2020-02-10
  • 2011-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
相关资源
最近更新 更多