主机对象应该被计为isPlainObject函数中的普通对象吗?

时间:2013-03-09 20:41:21

标签: javascript jquery javascript-objects lodash

我一直在不同浏览器上对不同库中的isPlainObject函数进行一些测试。

在各种对象上测试了4种不同的(代码方式)isPlainObject函数:

  • jquery的
  • lodash
  • 实用程序(我正在处理的库)
  • 替代方案,在下面的评论中提出

以上所有四项都显示了Chrome v23.0.1271.95到Chrome v25.0.1364.160,FireFox v 19.0和Opera v12.14之间的差异,但实用程序至少在这些对象上给出了相同的false响应浏览器

在Chrome上运行时

The tests on jsfiddle

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”构造的对象不同,所以我想我的问题是:主机对象应该算作普通对象吗?

目前,实用程序是一致的,并表示它们不是,其他例程为不同浏览器上的主机对象提供不同的结果。

编辑:结果的准确性对我来说是最重要的因素,性能是次要的考虑因素。

jsperf

提供了3个库的性能结果和建议的替代方案

编辑:这是实用程序库函数,因此您无需搜索代码。

defineProperty(utility, "isPlainObject", {
    value: (function () {
        var o = {};

        return function (obj) {
            try {
                return utility.isObject(obj) && getPrototypeOf(obj).isPrototypeOf(o);
            } catch (e) {
                return false;
            }
        };
    }())
});

1 个答案:

答案 0 :(得分:1)

  

以上三个都在FireFox v 19.0和Opera v12.14

上执行时通过了测试

不,至少在Opera中,window.screenMathJSONDOMErrorLSParserFilter,{{1} },DOMImplementationLSwindow.operaSVGException

  

这是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即可(如果您不需要支持跨框架对象)。 Objectnew Object个对象可以满足此要求。

  • 原型上没有干扰的可枚举属性

    然后你也可以允许getPrototypeOf(obj) == Object.prototype甚至手动检查像lodash这样的可枚举属性。现在,这将包括Math作为“普通对象”。

  • JSON

    创建

    然后还将[[Class]]的检查添加为getPrototypeOf(obj) == null,以排除Object.prototypenew ObjectObject等本地对象以及所有具有实现的主机对象 - 特定课程。你真的希望那些在测试JSON的函数中传递它们,如果它们通过其他测试它们会造成破坏吗?

另见Say what? at niftysnippets.org(T.J.Crowder的博客)