我一直在不同浏览器上对不同库中的isPlainObject函数进行一些测试。
在各种对象上测试了4种不同的(代码方式)isPlainObject函数:
以上所有四项都显示了Chrome v23.0.1271.95到Chrome v25.0.1364.160,FireFox v 19.0和Opera v12.14之间的差异,但实用程序至少在这些对象上给出了相同的false响应浏览器
在Chrome上运行时Failed to agree: JSON - jquery: true - utility: false - lodash: true - alt: false
Failed to agree: Math - jquery: true - utility: false - lodash: true - alt: false
Failed to agree: top - jquery: false - utility: false - lodash: true - alt: true
Failed to agree: parent - jquery: false - utility: false - lodash: true - alt: true
编辑:我相信所有例程都使用以下类似的条件:
jquery州
检查对象是否是普通对象(使用“{}”或“new Object”创建)。
lodash州
检查给定值是否是Object构造函数创建的对象。
我理解主机对象与使用“{}”或“new Object”构造的对象不同,所以我想我的问题是:主机对象应该算作普通对象吗?
目前,实用程序是一致的,并表示它们不是,其他例程为不同浏览器上的主机对象提供不同的结果。
编辑:结果的准确性对我来说是最重要的因素,性能是次要的考虑因素。
提供了3个库的性能结果和建议的替代方案编辑:这是实用程序库函数,因此您无需搜索代码。
defineProperty(utility, "isPlainObject", {
value: (function () {
var o = {};
return function (obj) {
try {
return utility.isObject(obj) && getPrototypeOf(obj).isPrototypeOf(o);
} catch (e) {
return false;
}
};
}())
});
答案 0 :(得分:1)
以上三个都在FireFox v 19.0和Opera v12.14
上执行时通过了测试
不,至少在Opera中,window.screen
,Math
,JSON
,DOMError
,LSParserFilter
,{{1} },DOMImplementationLS
,window.opera
和SVGException
。
这是Chrome / Chromium中的错误吗?
什么?不同的功能会产生不同的结果吗否。
对于四个对象中的每一个,正确的结果应该是什么(所以我可以确定哪个函数最准确)?
你如何定义“正确”?你如何定义“普通对象”?
我相信所有3个例程都使用以下标准:
检查对象是否是普通对象(使用“{}”或“new Object”创建)。
这几乎不是一个有用的标准,因为那些遇到差异的对象不会“创建” - 它们就是恰好存在的宿主对象(甚至是原生对象)。
然而,我们可以比较这些功能使用的标准:
jQuery 很奇怪;你可以阅读source code at github。简而言之:一个对象或函数,其[[Class]]不是document.implementation
之一,没有真正的Boolean Number String Function Array Date RegExp Error
属性,没有nodeName
属性指向自身,并且没有window
属性或constructor
的{{1}}属性具有自己的prototype
属性。
他们似乎是为了跨浏览器支持而这样做,但正如您所看到的那样,在某些情况下,您希望它不会成为普通对象。
实用程序有点混淆,但检查本身很简单:[[Class]]为constructor
且其原型为isPrototypeOf
的对象(或者更确切地说,其原型具有Object
方法,为Object.prototype
产生isPrototypeOf
。
Lodash 有一些奇怪的东西,比如jQuery,但不是那么难 - 你可以阅读source at github。它首先检查对象类型而不是null,然后从true
方法{}
获取Object.prototype
(如果存在)。如果找到一个,则对象或其原型必须是getPrototypeOf(getPrototypeOf(…))
对象,并且它不能是valueOf
对象。如果它没有找到,那么它会回到shim,我不会在这里解释。
所有这些都是为了支持使用不同的Object.prototype
对象和不提供Arguments
方法的浏览器检测来自不同环境(例如iframe)的普通对象。
“替代”实现:这会将对象的原型测试为Object.prototype
(但明确排除getPrototypeOf
)或{{1}并且[[Class]]值为null
。
应该将主机对象计为普通对象吗?
也许。它总是取决于你的用例......
表现得像是由Object.prototype
然后只需Object.prototype
即可(如果您不需要支持跨框架对象)。 Object
和new Object
个对象可以满足此要求。
原型上没有干扰的可枚举属性
然后你也可以允许getPrototypeOf(obj) == Object.prototype
甚至手动检查像lodash这样的可枚举属性。现在,这将包括Math
作为“普通对象”。
由JSON
然后还将[[Class]]的检查添加为getPrototypeOf(obj) == null
,以排除Object.prototype
,new Object
,Object
等本地对象以及所有具有实现的主机对象 - 特定课程。你真的希望那些在测试JSON
的函数中传递它们,如果它们通过其他测试它们会造成破坏吗?
另见Say what? at niftysnippets.org(T.J.Crowder的博客)