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

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

我想听听哪些更好,最重要的是为什么。 一个人明确比另一个好吗? 是否有不止两种方法来做对象属性检测? 请涵盖浏览器支持,陷阱,执行速度等等,而不是美学。

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

  • if(object.property)

    在没有设置(这是你想要的)的情况下会失败, 并且在某些情况下它被设置为falsey值,例如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或更低的情况下)。

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

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

笔记:

  • 避免主机对象的object.hasOwnProperty() ,因为主机对象不必从Object.prototypeinheritance,因此可能没有hasOwnProperty()方法(事实上在IE <9中,它们通常不会)。
  • 一个简单的布尔强制(例如, if (object.property) { ... } )是一个属性存在的一个糟糕的testing,因为它会给虚假价值的假阴性。 例如,对于空的textarea, if (textarea.selectionStart) { ... }即使该属性存在也不会执行该块。 此外,一些主机对象属性在尝试强制为布尔值时(例如, var xhr = new ActiveXObject("Microsoft.XMLHTTP"); if (xhr.responseXML) { ... } ),会在旧版本的IE中引发错误。
  • in运算符是一个属性存在的更好的testing,但是在host对象中对它的支持再次没有保证。
  • 我build议不要考虑这种任务的performance。 为您的项目select最安全的选项,稍后再进行优化。 几乎肯定会有比物业存在检查更好的候选人。

对于这个更多的背景,我推荐这篇由Peter Michaux撰写的优秀文章 。

当然, if ('property' in object)是正确的路要走。 这实际上testing属性是否在对象(或在其原型链,更多的下面)。

if (object.property)另一方面将“财产”强制为一个真理/价值的价值。 如果该属性未设置,它将返回“未定义”,这将被强制为假,并似乎工作。 但是对于其他一些属性值也会失败。 javascript在被视为真理和虚假的方面出了名的不一致。

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

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

如果“property”的值为0,那么第一个会失败。为了确保实际存在一个属性,您需要检查object.property !== undefined ,或者使用in-keyword。

[编辑]

还有hasOwnProperty函数,但我从来没有真正使用过,所以我不能说太多。 虽然我认为,如果财产设置在一个原型,有时你想要的,其他时候你不想要的,它不会返回真实。

这允许你使用window.hasOwnProperty作为引用自己或其他东西,不pipe你的脚本主机。

 // 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');