JavaScript对象检测:点语法与'in'关键字

Nic*_*nks 63 javascript properties

我已经看到了两种检测UA是否实现特定JS属性的方法:if(object.property)if('property' in object).

我想听听哪些更好,更重要的是为什么的意见.一个明显优于另一个吗?是否有不仅仅是这两种方法来进行对象属性检测?请涵盖浏览器支持,陷阱,执行速度等,而不是美学.

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

pim*_*vdb 116

  • if(object.property)

    将在未设置的情况下失败(这是你想要的),在情况下,它已经被设置为一些falsey值,例如undefined,null,0等(这是不是你想要的).

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

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

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

    甚至更好,因为它将允许您区分实例属性和原型属性.

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

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


编辑:你也可以通过传递任何东西(甚至不是对象的东西)作为一个对象来制作一个通用函数来检查属性是否存在:

function has(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
}
Run Code Online (Sandbox Code Playgroud)

现在这个工作:

has(window, 'setTimeout'); // true
Run Code Online (Sandbox Code Playgroud)

即使window.hasOwnProperty === undefined(IE版本8或更低版本的情况).

  • 如果`object`是一个宿主对象,那么`object.hasOwnProperty`是危险的,因为宿主对象没有义务从`Object.prototype`继承(实际上在IE <9中,它们通常不会),所以我建议反对那个. (3认同)

Tim*_*own 11

这真的取决于你想要达到的目标.您是在谈论主机对象(例如windowDOM节点)吗?如果是这样,最安全的检查是typeof,这适用于我所知道的所有主机对象:

 if (typeof object.property != "undefined") { ... }
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 避免object.hasOwnProperty()使用宿主对象,因为宿主对象没有义务继承Object.prototype,因此可能没有hasOwnProperty()方法(实际上在IE <9中,它们通常不会).
  • 一个简单的布尔强制(例如if (object.property) { ... })是对属性存在的不良测试,因为它会给出虚假值的假阴性.例如,对于空文本区域,if (textarea.selectionStart) { ... }即使属性存在,也不会执行该块.此外,在尝试强制转换为布尔值时,某些主机对象属性会在较旧版本的IE中引发错误(例如var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... }).
  • in操作是一个属性的存在的一个更好的测试,但再次没有关于主机对象对它的支持保障.
  • 我建议不要考虑这种任务的表现.为您的项目选择最安全的选项,并且仅在以后进行优化.几乎可以肯定,优化的候选者比财产存在检查要好得多.

有关这方面的更多背景,我推荐Peter Michaux撰写的这篇优秀文章.

  • @Ben Lee:另外,看一下ECMAScript 3规范的8.6.2节(它仍然是今天一般使用的浏览器集的基线),它特别声明主机对象可以选择实现或不执行任何内部方法它喜欢,包括`[[HasProperty]]`(这是`in`运算符所依赖的).所以简而言之,似乎规范说没有保证. (2认同)