Search code examples
javascriptarraysconstructorprototype

behaviour of changing [].__proto__.constructor and [].constructor differs


I'm currently trying to understand the constructor property in javascript.

Just a heads up, I understand changing the properties of builtin should be avoided, I'm playing around with it because I want to better understand the underlying principles.

I tried to change the default constructor property of [] (i.e. default constructor for array objects)

[].__proto__.constructor === [].constructor; // true 

[].constructor = function A(){}; // attempts to reset the constructor property to a new function 

[].constructor; // prints ƒ Array() { [native code] }, which indicate the attempt failed

But when I checked the property descriptor of [].constructor

Object.getOwnPropertyDescriptor([].__proto__, 'constructor');

which prints

{value: ƒ, writable: true, enumerable: false, configurable: true}

So the [].__proto__.constructor property is writable?

So I tries to set the constructor property via [].__proto__, it succeeded

[].__proto__.constructor = function B(){};

[].__proto__.constructor; //   prints: ƒ B(){}, which indicate the attempt succeded

Why changing the constructor property via [] failed but via [].__proto__ succeeded? Even though [].constructor === [].__proto__.constructor returned true.


Solution

  • This is due to property shadowing on the prototype chain. When you execute

    [].constructor = ...;
    

    this creates an instance property on the array that shadows the class prototype constructor. However, since Array.prototype already has its own constructor property, executing

    [].__proto__.constructor = ...;
    

    overwrites the constructor on Array.prototype.

    You can confirm this behavior by actually storing the array instance and looking closer at its prototype chain:

    enter image description here

    Below verifies that the assignment actually creates an own property on array1 which shadows the inherited property from Array.prototype.

    function A(){}
    
    var array1 = [];
    
    array1.constructor = A;
    
    console.log(array1.constructor === A);
    console.log(array1.__proto__.constructor === Array);