Sean
Sean

Reputation: 410

Confusing .constructor property in Javascript

The code below is what I test in browser.

function A(){}
a = new A()

a.__proto__ === a //false
a.__proto__.constructor === a.constructor //true

It's confusing for me why a.__proto__ and a share the same .constructor

Upvotes: 0

Views: 60

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1073998

a.__proto__ === a is false because a is not its own prototype. They're separate objects

a.__proto__.constructor === a.constructor is true because the a object inherits the constructor property from its prototype. So you can access the property on a (indirectly) or on its prototype.

When you do a = new A(), here's a rough idea of what you have in memory (handwaving away some details), which may help:

     +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
     |                                                             |
     |  +−−−−−−−−−−−−−−−+                                          |
A−−−−+−>|  (function)   |                                          |
        +−−−−−−−−−−−−−−−+                                          |
        | name: "A"     |                        +−−−−−−−−−−−−−−−+ |
        | prototype     |−−−−−−−−−−−−−−−−−−−−−+−>|   (object)    | |
        | [[Prototype]] |−>Function.prototype |  +−−−−−−−−−−−−−−−+ |
        | [[Code]]      |                     |  | constructor   |−+                
        +−−−−−−−−−−−−−−−+                     |  | [[Prototype]] |−>Object.prototype
                                              |  +−−−−−−−−−−−−−−−+
   +−−−−−−−−−−−−−−−+                          |  
a−>|   (object)    |                          |
   +−−−−−−−−−−−−−−−+                          |
   | [[Prototype]] |−−−−−−−−−−−−−−−−−−−−−−−−−−+
   +−−−−−−−−−−−−−−−+           

([[Prototype]] is a link to the object's prototype, the value returned by the deprecated __proto__ and by the modern Object.getPrototypeOf(). Also: Function.prototype's prototype is Object.prototype, not shown above.)

A is a constructor function. It has a property, prototype, which points to the object that will be used as the prototype of objects created via new A. a is an object created via new A, so its prototype ([[Prototype]]) is that same object. The A.prototype object has a property, constructor, that refers back to the constructor function it's associated with (in the simple, default case).

It becomes a bit more useful when you have two instances, a1 and a2. Let's modify the code a bit:

// Part 1
function A(foo) {
    this.foo = foo;
}
A.prototype.method = function() {
    console.log(this.foo);
};

// Part 2
const a1 = new A("one");
const a2 = new A("two");

a1.method(); // "one"
a2.method(); // "two"

After Part 1 above runs, we have something like this (again, leaving out some details, and I've used Fp and Op instead of Function.prototype and Object.prototype to save space):

     +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
     |                                           |
     |  +−−−−−−−−−−−−−−−+                        |
A−−−−+−>|  (function)   |                        |
        +−−−−−−−−−−−−−−−+                        |
        | name: "A"     |      +−−−−−−−−−−−−−−−+ |
        | prototype     |−−−−−>|   (object)    | |
        | [[Prototype]] |−>Fp  +−−−−−−−−−−−−−−−+ |
        | [[Code]]      |      | constructor   |−+    +−−−−−−−−−−−−−−−−+
        +−−−−−−−−−−−−−−−+      | method        |−−−−−>|   (function)   |
                               | [[Prototype]] |−>Op  +−−−−−−−−−−−−−−−−+
                               +−−−−−−−−−−−−−−−+      | name: "method" |
                                                      | [[Prototype]]  |−>Fp
                                                      | [[Code]]       |
                                                      +−−−−−−−−−−−−−−−−+

After the const a1 = new A("one"); line, we have:

     +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
     |                                              |
     |  +−−−−−−−−−−−−−−−+                           |
A−−−−+−>|  (function)   |                           |
        +−−−−−−−−−−−−−−−+                           |
        | name: "A"     |         +−−−−−−−−−−−−−−−+ |
        | prototype     |−−−−−−+−>|   (object)    | |
        | [[Prototype]] |−>Fp  |  +−−−−−−−−−−−−−−−+ |
        | [[Code]]      |      |  | constructor   |−+    +−−−−−−−−−−−−−−−−+
        +−−−−−−−−−−−−−−−+      |  | method        |−−−−−>|   (function)   |
                               |  | [[Prototype]] |−>Op  +−−−−−−−−−−−−−−−−+
                               |  +−−−−−−−−−−−−−−−+      | name: "method" |
                               |                         | [[Prototype]]  |−>Fp
                               |                         | [[Code]]       |
                               |                         +−−−−−−−−−−−−−−−−+
     +−−−−−−−−−−−−−−−+         |
a1−−>|   (object)    |         |
     +−−−−−−−−−−−−−−−+         |
     | foo: "one"    |         |
     | [[Prototype]] |−−−−−−−−−+
     +−−−−−−−−−−−−−−−+

After the const a2 = new A("two"); line, we have:

     +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
     |                                              |
     |  +−−−−−−−−−−−−−−−+                           |
A−−−−+−>|  (function)   |                           |
        +−−−−−−−−−−−−−−−+                           |
        | name: "A"     |         +−−−−−−−−−−−−−−−+ |
        | prototype     |−−−−−−+−>|   (object)    | |
        | [[Prototype]] |−>Fp  |  +−−−−−−−−−−−−−−−+ |
        | [[Code]]      |      |  | constructor   |−+    +−−−−−−−−−−−−−−−−+
        +−−−−−−−−−−−−−−−+      |  | method        |−−−−−>|   (function)   |
                               |  | [[Prototype]] |−>Op  +−−−−−−−−−−−−−−−−+
                               |  +−−−−−−−−−−−−−−−+      | name: "method" |
                               |                         | [[Prototype]]  |−>Fp
                               |                         | [[Code]]       |
                               |                         +−−−−−−−−−−−−−−−−+
     +−−−−−−−−−−−−−−−+         |
a1−−>|   (object)    |         |
     +−−−−−−−−−−−−−−−+         |
     | foo: "one"    |         |
     | [[Prototype]] |−−−−−−−−−+
     +−−−−−−−−−−−−−−−+         |
                               |
     +−−−−−−−−−−−−−−−+         |
a2−−>|    (object)   |         |
     +−−−−−−−−−−−−−−−+         |
     | foo: "two"    |         |
     | [[Prototype]] |−−−−−−−−−+
     +−−−−−−−−−−−−−−−+

That shows how the prototype is useful for shared features. a1 and a2 don't need to have their own copies of method, they just inherit it from their prototype.


Side note: __proto__ is deprecated. Use Object.getPrototypeOf(a) to get the prototype of a, rather than a.__proto__.

Upvotes: 4

Amadan
Amadan

Reputation: 198304

A.prototype.constructor == A for any function A; a.__proto__ == A.prototype for any object a constructed by new A; a.constructor doesn't exist, so it is looked up up the prototype chain just like any other attribute, and is found at a.__proto__.constructor.

Upvotes: 2

Related Questions