Why in JavaScript both “Object instanceof Function” and “Function instanceof Object” return true?

前端 未结 7 1161
梦如初夏
梦如初夏 2020-11-27 03:33

Why in JavaScript do both Object instanceof Function and Function instanceof Object return true?

I tried it in Safari WebInspe

相关标签:
7条回答
  • 2020-11-27 04:01

    ALL objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. If you try to look up a key on an object and it is not found, JavaScript will look for it in the prototype chain.

    The Function constructor creates new Function objects (instances of Function constructor). The prototype property is specific to Function objects. The Function constructor is itself a Function object (instance of Function constructor).

    When a Function object is used as a constructor, a new object will be created and the new object will have its [[Prototype]] initialized with the prototype property of the constructor.

    function Dog () {}
    var myCrazyDog = new Dog();
    myCrazyDog.__proto__ === Dog.prototype // true
    

    The language spec is that all objects are instances of Object constructor, and all functions are instances of Function constructor.

    Object instanceof Function is true because Object is a function and thus is an instance of Function (Object is a Function object - an instance of the Function constructor). Object inherits from Function.prototype.

    console.log(Object instanceof Function)                         // true
    console.log(Object.__proto__ === Function.prototype)            // true
    

    Object instanceof Object is true because Object inherits from Function.prototype. Since Function.prototype is an object, it inherits from Object.prototype. Function instance of Object is true because Function inherits from Function.prototype. Since Function.prototype is an object, it inherits from Object.prototype. The prototype chain looks like this:

    Object ---> Function.prototype ---> Object.prototype ---> null
    Function ---> Function.prototype ---> Object.prototype ---> null
    
    console.log(Object instanceof Object)                               // true
    console.log(Object.__proto__ === Function.prototype)                // true
    console.log(Object.__proto__.__proto__ === Object.prototype)        // true
    console.log(Function instanceof Object)                             // true
    console.log(Function.__proto__ === Function.prototype)              // true
    console.log(Function.__proto__.__proto__ === Object.prototype)      // true
    

    Function instanceof Function is true. Function is an instance of itself (naturally, since it’s a function, and thus an instance of Function). The prototype chain looks like this:

    Function ---> Function.prototype ---> Object.prototype ---> null
    
    console.log(Function instanceof Function)                           // true
    console.log(Function.__proto__ === Function.prototype)              // true
    console.log(Function.__proto__.__proto__ === Object.prototype)      // true
    

    Thus keep in mind that the Function() and Object() constructors are functions. Since they are functions they are instances of the Function() constructor and inheriting from Function.prototype. Since Function.prototype is an object, Function.prototype is an instance of Object, thus inheriting from Object.prototype.

    console.log(Object instance of Function)                    // true
    console.log(Function instance of Function)                  // true
    console.log(Function.prototype instanceof Object);          // true
    
    0 讨论(0)
  • 2020-11-27 04:04

    The source of the confusion in your question lies in the inherent dual nature of functions* in JavaScript (ECMAScript).

    Functions in js are both regulars functions and objects at the same time. Think of them as algorithmic Dr. Jekyll and Mr. Hyde. They look like objects on the outside but inside they're just your good old js functions with all their quirks, or maybe it's the other way around!

    JavaScript is really a tricky business :)

    So back to your question, borrowing the syntax appearing on MDN:

    object instanceof constructor

    Applying it on the first statement in your code:

    Object instanceof Function

    Here you have Object, a constructor function that's used as an object initializer but since functions lead a double life in js, it has object-specific props and methods attached to it rendering it effectively an object too.

    So, the first condition in the statement has been met. We remain to investigate the other condition or operand.

    Function as you might have noticed is also function constructor but its other object side is of no interest to us now during the execution of this particular statement.

    So, the syntactic conditions are both met namely "object" and "constructor". We can now then proceed to investigate their hereditary relation and if there's a connection between them.

    Since Object is a working function itself, it makes a lot of sense to assume that it has its internal prototype prop pointing to the Function.prototype object reference since in js ALL functions inherit their props and methods through that same location Function.prototype.

    true is definitely the ONLY expected outcome of this comparison performed by the instanceof operator.

    For the other case:

    Function instanceof Object

    Since we established already that functions in js have also an object side to them. It makes sense that they got their fancy object-specific toys from the Object.prototype, and therefore they constitute instances of the Object constructor.

    Hope I didn't add to the confusion with my explanation and allegories. :)

    *: Not only functions that lead a double life in js. Almost all data types in js have an object dark side to them that facilitate completing operations and manipulations without any hassle.

    0 讨论(0)
  • 2020-11-27 04:06

    Very Simple Explanation, Different from all answers

    Both Object and Function are constructors(type of both with return "Function objects") and both are created from Function Constructor. The __proto__ property of both these point to 'Function.prototype' object.

    QUICK EXPLANATION: __proto__ property of an object(say p1 which is Person type) points to the Constructor's protoype(say Person.prototype) Again the __proto__ in the prototype chain points to the object "Object.prototype".

    BEFORE READING FURTHER PRINT DETAILS ON CHROME CONSOLE console.dir(Object), console.dir(Function)

    KEEP IN MIND, function constructors and also objects so you will see both .prototype and __proto__ properties. In all the instance objects(say p1) you will only find the __proto__ property. The __proto__ is accessor for hidden property [[Prototye]] and best way to get is Object.getPrototypeOf(p1) as __proto__ is depricated.

    (p1 instanceof Person) here operator checks if the Constructor Person's prototype is in the prototypal chain of the object p1. take a note that first value is instance object(p1) and second value is a constructor (Person).

    Lets analyze => Function instanceof Object.

    Function object's __proto__.__proto__ points to Object.prototype , So its true

    Lets analyze => Object instanceof Function.

    Object object's __proto__ points to Function.prototype, So its true

    Hope this helps.

    0 讨论(0)
  • 2020-11-27 04:12

    It took a while for me to figure out but its really worth the time spent. First, let us see how instanceof works.

    Quoting from MDN,

    The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

    [instanceof]

    Now, let us see how instanceof is defined by ECMA 5.1 Specification,

    The production RelationalExpression: RelationalExpression instanceof ShiftExpression is evaluated as follows:

    1. Let lref be the result of evaluating RelationalExpression.
    2. Let lval be GetValue(lref).
    3. Let rref be the result of evaluating ShiftExpression.
    4. Let rval be GetValue(rref).
    5. If Type(rval) is not Object, throw a TypeError exception.
    6. If rval does not have a [[HasInstance]] internal method, throw a TypeError exception.
    7. Return the result of calling the [[HasInstance]] internal method of rval with argument lval.

    First the left and right hand side expressions are evaluated (GetValue) and then right hand side result should be an Object with [[HasInstance]] internal method. Not all objects will have [[HasInstance]] internal method, but functions. For example, the following will fail

    console.log(Object instanceof {});
    # TypeError: Expecting a function in instanceof check, but got #<Object>
    

    [[HasInstance]]

    Now, let us see how [[HasInstance]] has been defined in the ECMA 5.1 specification,

    Assume F is a Function object.

    When the [[HasInstance]] internal method of F is called with value V, the following steps are taken:

    1. If V is not an object, return false.
    2. Let O be the result of calling the [[Get]] internal method of F with property name "prototype".
    3. If Type(O) is not Object, throw a TypeError exception.
    4. Repeat
      1. Let V be the value of the [[Prototype]] internal property of V.
      2. If V is null, return false.
      3. If O and V refer to the same object, return true.

    It is so simple. Take the prototype property of F and compare it with the [[Prototype]] internal property of O until it becomes null or prototype of F is the same as O.

    [[prototype]] internal property

    First let us see what is the [[prototype]] internal property,

    All objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. Whether or not a native object can have a host object as its [[Prototype]] depends on the implementation. Every [[Prototype]] chain must have finite length (that is, starting from any object, recursively accessing the [[Prototype]] internal property must eventually lead to a null value).

    Note: We can get this internal property with the Object.getPrototypeOf function.

    prototype property

    [[HasInstance]] also talks about another property called prototype, which is specific to the Function objects.

    The value of the prototype property is used to initialise the [[Prototype]] internal property of a newly created object before the Function object is invoked as a constructor for that newly created object.

    This means that, when a function object is used as a constructor, a new object will be created and the new object will have its internal [[Prototype]] initialized with this prototype property. For example,

    function Test() {}
    Test.prototype.print = console.log;
    console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
    # true
    

    Actual problem

    Now let us get back to the actual question. Lets take the first case

    console.log(Object instanceof Function);
    # true
    

    It will fetch Function.prototype first and it will try and find if that object is in the prototype hierarchy of Object. Let us see how that turns out

    console.log(Function.prototype);
    # [Function: Empty]
    console.log(Object.getPrototypeOf(Object));
    # [Function: Empty]
    console.log(Object.getPrototypeOf(Object) === Function.prototype);
    # true
    

    Since the Function.prototype matches the Object's internal property [[Prototype]], it returns true.

    Now lets take the second case

    console.log(Function instanceof Object);
    # true
    console.log(Object.prototype);
    # {}
    console.log(Object.getPrototypeOf(Function));
    # [Function: Empty]
    console.log(Object.getPrototypeOf(Function) === Object.prototype);
    # false
    console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
    # {}
    Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
    # true
    

    Here, first we get the Object.prototype, which is {}. Now it is trying to find if the same object {} is there in the Function's prototype chain. Immediate parent of Function is and Empty function.

    console.log(Object.getPrototypeOf(Function));
    # [Function: Empty]
    

    It is not the same as Object.prototype

    console.log(Object.getPrototypeOf(Function) === Object.prototype);
    # false
    

    But the [[HasInstance]] algorithm doesn't stop there. It repeats and gets up one more level

    console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
    # {}
    

    And this is the same as Object.prototype. That is why this returns true.

    0 讨论(0)
  • 2020-11-27 04:12

    From MDN:

    The instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

    Essentially, it is checking if Object (not an instance of Object, but the constructor itself) has as an instance of Function.constructor somewhere up its prototype chain.

    And, indeed:

    > Function.__proto__.__proto__ === Object.prototype
    true
    > Object.__proto__ === Function.prototype
    true
    

    This explains why Object instanceof Function as well as the reverse.

    0 讨论(0)
  • 2020-11-27 04:15

    Object is a built-in constructor function for objects. It is therefore a function (an instance of Function). Functions are objects in JavaScript, it is therefore an object too (an instance of Object).

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