【问题标题】:JavaScript object detection: dot syntax versus 'in' keywordJavaScript 对象检测:点语法与“in”关键字
【发布时间】:2011-11-02 17:40:23
【问题描述】:

我见过两种检测 UA 是否实现特定 JS 属性的方法:if(object.property)if('property' in object)

我想听听关于哪个更好的意见,最重要的是,为什么。一个明确地比另一个更好吗?除了这两种方法可以进行对象属性检测吗?请涵盖浏览器支持、陷阱、执行速度等,而不是美学。

编辑:鼓励读者在jsperf.com/object-detection运行测试

【问题讨论】:

    标签: javascript properties


    【解决方案1】:

    如果“property”为 false 为 0,第一个将失败。要确保确实存在属性,您需要检查 object.property !== undefined,或使用 in-keyword。

    [编辑]

    还有hasOwnProperty-function,但我从来没有真正使用过那个,所以我不能多说。虽然我认为如果属性设置在原型中,它不会返回 true,有时你想要,有时你不想要。

    【讨论】:

    • 属性可以存在但未定义。 (如果你想测试不确定性,那么typeof object.property === "undefined" 更安全)。
    • 将属性设置为 undefined 与删除它不一样吗?或者,如果您遍历属性,它仍然会显示吗?
    • @Alexandr,不,不一样。试试a = {}; a.x = undefined; a.hasOwnPropety('x') == true; a.hasOwnProperty('y') == false;
    • 要删除属性,请执行delete object.property
    • 嗯。不知道。那是关于将属性设置为未定义实际设置属性的部分。不过我知道 delete 关键字。只是以为他们也做了同样的事情。
    【解决方案2】:
    • if(object.property)

      如果未设置(这是您想要的)将失败,如果它已设置为一些虚假值,例如undefinednull0 等(这不是你想要的)。

      var object = {property: 0};
      if(object.isNotSet) { ... } // will not run
      if(object.property) { ... } // will not run
      
    • if('property' in object)

      稍微好一点,因为它实际上会返回对象是否真的具有该属性,而不仅仅是查看它的值。

      var object = {property: 0};
      if('property' in object) { ... } // will run
      if('toString' in object) { ... } // will also run; from prototype
      
    • if(object.hasOwnProperty('property'))

      更好,因为它可以让您区分实例属性和原型属性。

      var object = {property: 0};
      if(object.hasOwnProperty('property')) { ... } // will run
      if(object.hasOwnProperty('toString')) { ... } // will not run
      

    我想说性能在这里并不是什么大问题,除非您每秒检查数千次,但在这种情况下,您应该考虑另一种代码结构。最近的浏览器都支持所有这些函数/语法,hasOwnProperty 也已经存在很长时间了。


    编辑:您还可以通过将任何东西(甚至不是对象的东西)作为对象传递来创建一个通用函数来检查属性的存在,如下所示:

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

    现在可以了:

    has(window, 'setTimeout'); // true
    

    即使window.hasOwnProperty === undefined(在 IE 版本 8 或更低版本中就是这种情况)。

    【讨论】:

    • 我同意这里的性能考虑无关紧要(即使对于数十万次比较,差异也不重要,因为速度如此之快)。但是从学术上考虑,如果有的话if (object.hasOwnProperty)最快的,因为它只是检查内存中的对象的属性。另外两个有更多的工作要做。 if ('property' in object) 已检查对象中的属性,但如果未找到该属性,还要检查原型链。 if (object.property) 必须检查对象中的属性,然后在大多数情况下还要进行类型强制。
    • object.hasOwnProperty 如果object 是主机对象,则很危险,因为主机对象没有义务从Object.prototype 继承(实际上在 IE
    • @Ben Lee:我认为你是对的。但是,调用函数通常会比较慢,所以我不太确定。
    • @Tim Down:谢谢,很高兴知道。我会试着摆弄一下,看看 IE 是如何处理它的。
    • @Ben Lee:结果在 Chrome 上有所不同:jsperf.com/object-detection
    【解决方案3】:

    if ('property' in object) 绝对是正确的选择。这实际上测试了属性是否在对象中(或其原型链中,更多内容见下文)。

    另一方面,if (object.property) 会将“属性”强制转换为真值/flase 值。如果该属性未设置,它将返回“未定义”,这将被强制为 false,并且似乎可以工作。但这对于许多其他设置的属性值也会失败。众所周知,javascript 在其认为是真值和假值方面是不一致的。

    最后,就像我上面所说的,'property' in 'object' 将在原型链中的任何位置返回 true。如果您想在对象本身上进行测试,而不是在链中更高的位置,您可以使用 hasOwnProperty 方法,如下所示:

    if (object.hasOwnProperty('property')) ...
    

    【讨论】:

      【解决方案4】:

      这真的取决于你想要实现什么。您是在谈论主机对象(例如 window 和 DOM 节点)吗?如果是这样,最安全的检查是typeof,它适用于我知道的所有主机对象:

       if (typeof object.property != "undefined") { ... }
      

      注意事项:

      • 避免将object.hasOwnProperty() 用于宿主对象,因为宿主对象没有义务从Object.prototype 继承,因此可能没有hasOwnProperty() 方法(实际上在IE
      • 一个简单的布尔强制转换(例如if (object.property) { ... })对于属性是否存在的测试效果不佳,因为它会为虚假值提供假阴性。例如,对于一个空的 textarea,if (textarea.selectionStart) { ... } 将不会执行该块,即使该属性存在。此外,当尝试强制转换为布尔值时,某些主机对象属性会在旧版本的 IE 中引发错误(例如var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... })。
      • in operator 是对属性是否存在的更好测试,但再次不能保证主机对象支持它。
      • 我建议不要考虑此类任务的性能。为您的项目选择最安全的选项,然后再进行优化。几乎肯定会有比属性存在性检查更好的优化候选者。

      有关这方面的更多背景,我推荐this excellent article by Peter Michaux

      【讨论】:

      • 您确定in 运算符不一定可用于主机对象吗?毕竟,它是一个在对象上工作的运算符。而且我认为 javascript 中的所有对象,包括主机对象,基本上仍然是一组属性/值对,所以 in 运算符应该适用,对吧?
      • @Ben Lee:我不确定它是否会抛出错误,但它对于主机对象并不完全可靠。它不适用于检测 Firefox 中的事件处理程序属性,例如:"onmouseover" in document 返回false。从谷歌搜索来看,支持实际上似乎比我记得的要好:我能找到的最好的是在 cmets 中提到 kangax 到以下内容:nczonline.net/blog/2010/07/27/…
      • @Ben Lee:另外,查看 ECMAScript 3 规范的第 8.6.2 节(这仍然是当今通用浏览器集的基线),它特别指出主机对象可以选择实现或不实现它喜欢的任何内部方法,包括[[HasProperty]](这是in 运算符所依赖的)。所以简而言之,规范似乎说没有保证。
      【解决方案5】:

      这允许您使用 window.hasOwnProperty 来引用自身或其他内容,而不管您的脚本主机如何。

      // No enclosing functions here
      if (!('hasOwnProperty' in this))
          function hasOwnProperty(obj, prop) {
              var method = Object.prototype.hasOwnProperty;
              if (prop === undefined)
                  return method.call(this, obj);
              return method.call(obj, prop);
          }
      
      //Example of use
      var global = global || this; //environment-agnostic way to get the global object
      var x = 'blah';
      WScript.Echo(global.hasOwnProperty('x') ? 'true' : 'false'); //true
      
      //Use as non-object method
      var y = { z: false };
      WScript.Echo(hasOwnProperty(y, 'z') ? 'true' : 'false'); //true
      WScript.Echo(hasOwnProperty(y, 'w') ? 'true' : 'false'); //false
      
      // true ಠ_ಠ
      WScript.Echo(hasOwnProperty(global, 'hasOwnProperty') ? 'true' : 'false');
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-11
        • 1970-01-01
        • 1970-01-01
        • 2019-01-30
        相关资源
        最近更新 更多