简体   繁体   中英

JavaScript obj.constructor vs obj.[[Prototype]]'s constructor

Object.getPrototypeOf(z).constructor === z.constructor

Is this true for every object z in JavaScript?

I mean is z.constructor just a shortcut allowing us to retrieve more easily
the constructor property of the object's internal [[Prototype]] property.

Or... are there cases in which the two differ and the z.constructor value
is different from the Object.getPrototypeOf(z).constructor value?

I think it is just shortcut but I am not sure as I don't find
this stated explicitly in any authoritative source of doc.

EDIT : This code below shows that setting Object.getPrototypeOf(z).constructor implicitly sets the other value too. But setting z.constructor does not set the other value.
So now I am puzzled... how is this implemented? Seems z.constructor is not just a shortcut but some sort of copy. But if it's a copy why is it affected when we change/set the Object.getPrototypeOf(z).constructor to a new value?

    function Animal() {

        this.ttype = "Animal"

    }

    function Plant(){
        this.ttype = "Plant"
    }

    var p1 = new Plant();
    console.log(p1.constructor);
    console.log(p1.constructor === Object.getPrototypeOf(p1).constructor);
    p1.constructor = Animal;
    console.log(p1.constructor === Object.getPrototypeOf(p1).constructor);

    var p2 = new Plant();
    console.log(p2.constructor);
    console.log(p2.constructor === Object.getPrototypeOf(p2).constructor);
    Object.getPrototypeOf(p2).constructor = Animal;
    console.log(p2.constructor === Object.getPrototypeOf(p2).constructor);
    console.log(p2.constructor);

The constructor property of an object is normally inherited from it's prototype chain. There are two exceptions:

  1. Objects whose prototype chain doesn't contain any objects. These be created using Object.create(null) and are useful for setting up look up tables that aren't affected by properties inherited from somewhere else.

  2. Objects that have been assigned a local "own" property called constructor , as in

    myObject.constructor = 42;

    However, this is a technicality and not something you would expect to see in real code.

So leaving these aside, where is constructor inherited from?

By language design, constructor is inherited from the constructor function's prototype property. Every plain vanilla function in JavaScript is set up with a prototype property with a non enumerable property called constructor set to the function object itself. By this means any standard function can be called as a constructor without modification. However the overhead is that standard functions never intended to be used as constructors have a prototype property anyway.

Now more complications:

  1. The prototype property of a standard function object is writable. If it is updated to a new object value, objects constructed by the function will inherit constructor from the ammended prototype object - which would generally be different to the constructor value of the overwritten prototype value.

  2. The constructor property of the prototype property of a function is not write protected.

    • In combination, these two factors allow setting up prototype chains of arbitrary length, simulating in part the extension of classes in a class based language. EG If C objects inherit from B which inherit from A you could write

      B.prototype = new A() // B objects inherit from an instance of A, // which inherits from A.prototype C.prototype = new B() // C objects inherit from an instance of B, // which inherits from B.prototype and A.prototype C.prototype.constructor = C; // C objects inherit C as their constructor.

These classic rules for chaining prototypes are quite lax: you can change the prototype property multiple times without affecting the inheritance chain of previously created objects. However changing the prototype property of a constructor function multiple times has limited use (creating a polyfill for Object.create perhaps) and most unusual.

Note the class keyword syntax to create constructor functions renders this kind of manipulation obsolete - you can't change a class constructor functions prototype property, and if you extend a "class" the prototype property of the extended class inherits from the base class's prototype property while having its constructor property set to the extended constructor, both automatically.

Also note that arrow functions don't have a prototype property and cannot be used as constructors.


q1

Object.getPrototypeOf(z).constructor === z.constructor
Is this true for every object z in JavaScript?

Yes, except for the exceptions listed under 1) and 2).

q2

p1.constructor = Animal;

This creates an own property of p1 that shadows the inherited constructor property which can no longer be accessed (exception 2)

q3

Object.getPrototypeOf(p2).constructor = Animal;

This line of code updates the constructor property of the object from where p2 inherits its constructor value from, so p2 's inherited constructor property is now Animal . Other plant objects which similarly inherit from Plant.prototype would also see Animal as their constructor.

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