简体   繁体   中英

Javascript: typeof and instanceof results contradicting?

I am seeing contradicting results when doing typeof and instanceof on an object.

I have the following test page:

<html>
    <body>
        <object id="test" />
        <script type="text/javascript">
            var foo = document.getElementById("test");
            console.log(typeof foo); // returns "function"
            console.log(foo instanceof Function); // returns false
            console.log(foo instanceof Object); // returns true
        </script>
    </body>
</html>

"typeof foo" is returning "function" but "foo instanceof Function" is returning false.

This doesn't make sense to me. How can an object have a type be function but not be an instance of a function? Also, I expected "typeof foo" to return "object".

object and embed HTML elements are host objects.

ECMAScript3 11.4.3 didn't define what typeof should return for these. The table of returned values for Objects was

  • Object (native and doesn't implement [[Call]]): "object"
  • Object (native and implements [[Call]]): "function"
  • Object (host): Implementation-dependent

However, returning "function" is consistent with ECMAScript5 11.4.3 :

  • Object (native and does not implement [[Call]]): "object"
  • Object (native or host and does implement [[Call]]): "function"
  • Object (host and does not implement [[Call]]): Implementation-defined except may not be "undefined" , "boolean" , "number" , or "string" .

object and embed HTML elements are objects with an internal [[Call]] property, so typeof must return "function" .

This is explained in Bug 268945 :

  • Comment #15 , by Boris Zbarsky:

    The [[Call]] is very intentional on the DOM side: these are callable objects.

  • Comment #16 , by Tom Schuster:

    This bug is invalid these object have a [[Call]] internal method and ES5 11.4.3 explicitly say "Object (native or _host_ and does implement [[Call]])" => "function".

Since object and embed HTML elements implement an internal [[Call]] property, they are callable objects . However, they are not functions:

4.3.24 function

member of the Object type that is an instance of the standard built-in Function constructor and that may be invoked as a subroutine

object HTML elements inherit from HTMLObjectElement.prototype , and embed HTML elements from HTMLEmbedElement.prototype .

The prototype chain continues with

  • HTMLObjectElement.prototype
  • HTMLElement.prototype
  • Element.prototype
  • Node.prototype
  • Object.prototype

Therefore, they are not Function instances, because they don't inherit from Function.prototype .

The essential fact is that DOM elements (obtained, for example, using document.getElementById() ) are not native JavaScript objects. Instead, they are host objects . As such, they are not subject to the usual rules that apply to native JavaScript objects, and their behaviour will (quite legitimately) vary wildly from one browser to the next.

In short, all bets are off. Don't rely on the behaviour of host objects outside of their documented API.

Related references:

Safari returns ' function ' for typeof document.getElementsByTagName('p') ,

which gave me a bad time a while ago, when I assumed all clients would return 'object'.

It is good to test our pre-conceptions, even when an exception makes no sence.

Also, debuggers are lovely, but they do not always report the same values as their browser.

In your first example this dom element does not exist when the script is run. In your second it does, the answers are correct in the second the difference is between typeof and constructor. typeof returns a function because document.getElementById returns a function. constructor tells you the name of that function "HTMLElement".

you could for example invent your own elements starting with var myElement = new HTMLElement()

I'm not sure why 'function' is returned for a <object> node, but the reason instaceof Function fails is because that's essentially a check against the constructor, the difference of which can be illustrated like so

<html>
    <body>
        <object id="test" />
        <script type="text/javascript">

            var foo = document.getElementById("test");

            var bar = function() {}

            console.log( typeof foo );
            console.log( foo instanceof Function );
            console.log( foo.constructor ); // Object()

            console.log( typeof bar );
            console.log( bar instanceof Function );
            console.log( bar.constructor ); // Function()

        </script>
    </body>
</html>

So in this case, it's actually typeof that is behaving oddly, and not in a way that is documented that I can see.

I found some additional strange behavior.

If you move the javascript code above the object, then typeof works correctly but instanceof does not work.

<html>
<body>
    <script type="text/javascript">
        var foo = document.getElementById("test");
        console.log(typeof foo); // returns object (this is correct now)
        console.log(foo instanceof Function); // returns false (this is correct)
        console.log(foo instanceof Object); // returns false (this is wrong)
        console.log(foo instanceof HTMLElement); // returns false (this is wrong)
        console.log(foo instanceof Node); // returns false (this is wrong)
    </script>
    <object id="test" />
</body>

VS

<html>
<body>
    <object id="test" />
    <script type="text/javascript">
        var foo = document.getElementById("test");
        console.log(typeof foo); // returns function (this is wrong)
        console.log(foo instanceof Function); // returns false
        console.log(foo instanceof Object); // returns true (this is correct)
        console.log(foo instanceof HTMLElement); // returns true (this is correct)
        console.log(foo instanceof Node); // returns true (this is correct)
    </script>
</body>

So basically if the script is below the object, typeof behaves strangely but if the script is above the object instanceof behaves strangely.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM