Should host objects be counted as plain objects in an isPlainObject function?

前端 未结 1 660
情书的邮戳
情书的邮戳 2020-12-12 06:17

I\'ve been doing some testing of isPlainObject functions from different libraries on different browsers.

There are 4 different (code wise) isPlainObject functions be

1条回答
  •  粉色の甜心
    2020-12-12 06:45

    All three of the above pass the tests when executed on FireFox v 19.0 an Opera v12.14

    No, at least in Opera the tests in the fiddle fail for window.screen, Math, JSON, DOMError, LSParserFilter, DOMImplementationLS, window.opera, SVGException, and document.implementation.

    Is this a bug in Chrome/Chromium?

    What? That different functions return different results? No.

    And for each of the four objects, what should the correct result be (so I can determine which function is the most accurate)?

    How do you defined "correct"? How do you defined "plain object"?

    I believe that all 3 routines are using the following criteria:

    Check to see if an object is a plain object (created using "{}" or "new Object").

    That's hardly a useful criterion, since those objects where you experience discrepancies are not "created" - they are host objects (or even native objects) that just happen to exist.

    Yet, we could compare which criteria those functions use:

    • jQuery is very odd; you can read it's source code at github. In short: An object or function, whose [[Class]] is not one of Boolean Number String Function Array Date RegExp Error, that has not a truthy nodeName property, that has not a window property pointing to itself, and that has no constructor property or whose prototype property of the constructor has an own isPrototypeOf property.

      They seem to do this for cross-browser support, but as you can see it fails in some cases where you would have it expected not to be a plain object.

    • Utility is a bit obfuscated, but the check itself is simple: An object whose [[Class]] is Object and whose prototype is Object.prototype (or rather, whose prototype has a isPrototypeOf method that yields true for {}).

    • Lodash has a few oddities like jQuery, but not that hard - you can read the source at github. It first checks for object type and not null, then gets Object.prototype via getPrototypeOf(getPrototypeOf(…)) from a valueOf method if it exists. If it found one, either the object or its prototype must be that Object.prototype object and it must not be an Arguments object. If it did not found one, it falls back to the shim which I'm not going to explain here.

      All these things are done to support detecting plain objects from different environments (e.g. iframes) with a different Object.prototype object and in browsers that do not provide a getPrototypeOf method.

    • "Alternative" implementation: This tests the prototype of the object to be either null (but explicitly excluding Object.prototype) or to be Object.prototype and the [[Class]] value to be Object.

    should host objects be counted as plain objects?

    Maybe. It always depends on your use case…

    • act like it was created by new Object

      Then just getPrototypeOf(obj) == Object.prototype should be fine (if you don't need to support cross-frame objects). The Math and JSON objects would fulfill this requirement.

    • Have no interfering enumerable properties on the prototypes

      Then you might also allow getPrototypeOf(obj) == null or even manually check for enumerable properties like lodash does. This would now include Object.prototype as a "plain object" for example.

    • creatable by new Object

      Then also add the check for [[Class]] to be Object to exclude native objects like JSON, Math, Arguments and all those host objects with implementation-specific classes. Would you really expect those to be passed in the functions that test isPlainObject, and would they cause havoc if they passed the other tests?

    See also Say what? at niftysnippets.org (blog by T.J.Crowder)

    0 讨论(0)
提交回复
热议问题