Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it impossible to change constructor function from prototype?

I have such example.

function Rabbit() {     var jumps = "yes"; }; var rabbit = new Rabbit(); alert(rabbit.jumps);                    // undefined alert(Rabbit.prototype.constructor);    // outputs exactly the code of the function Rabbit(); 

I want to change the code in Rabbit() so that the var jumps becomes public. I do it this way:

Rabbit.prototype.constructor = function Rabbit() {     this.jumps = "no"; }; alert(Rabbit.prototype.constructor);    // again outputs the code of function Rabbit() and with new this.jumps = "no"; var rabbit2 = new Rabbit();             // create new object with new constructor alert(rabbit2.jumps);                   // but still outputs undefined 

Why is it not possible to change the code in constructor function this way?

like image 345
Green Avatar asked Feb 13 '12 19:02

Green


People also ask

What is the difference between constructor and prototype?

A prototype is just an object, while a constructor is a pointer to the function that created the object. A constructor is a pointer. It points to the Function() that created the point from which you are retrieving the constructor from.

What is constructor function prototype?

constructor. The constructor property returns a reference to the Object constructor function that created the instance object. Note that the value of this property is a reference to the function itself, not a string containing the function's name.

What is the difference between __ proto __ and prototype?

prototype is a property of a Function object. It is the prototype of objects constructed by that function. __proto__ is an internal property of an object, pointing to its prototype.

Why do some constructors work without new keyword?

Constructors requires the use of the new operator to create a new instance, as such invoking a class without the new operator results in an error, as it's required for the class constructor to create a new instance.


1 Answers

You cannot change a constructor by reassigning to prototype.constructor

What is happening is that Rabbit.prototype.constructor is a pointer to the original constructor (function Rabbit(){...}), so that users of the 'class' can detect the constructor from an instance. Therefore, when you try to do:

Rabbit.prototype.constructor = function Rabbit() {     this.jumps = "no"; }; 

You're only going to affect code that relies on prototype.constructor to dynamically instantiate objects from instances.

When you call new X, the JS engine doesn't reference X.prototype.constructor, it uses the X as the constructor function and X.prototype as the newly created object's prototype., ignoring X.prototype.constructor.

A good way to explain this is to implement the new operator ourselves. ( Crockford will be happy, no more new ;)

// `new` emulator  //   // Doesn't reference `.constructor` to show that prototype.constructor is not used  // when istantiating objects a la `new`  function make(ctorFun, argsArray) {    // New instance attached to the prototype but the constructor    // hasn't been called on it.    const newInstance = Object.create(ctorFun.prototype);    ctorFun.apply(newInstance, argsArray);    return newInstance;  }    // If you create a utility function to create from instance, then it uses the  // inherited `constructor` property and your change would affect that.  function makeFromInstance(instance, argsArray) {    return make(instance.constructor, argsArray);  }    function X(jumps) {    this.jumps = jumps;  }    // Flip the constructor, see what it affects  X.prototype.constructor = function(jumps) {    this.jumps = !jumps;  }    const xFromConstructorIsGood = make(X, [true]);  const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]);    console.log({    xFromConstructorIsGood,    xFromInstanceIsBad  });

Inheritance in JS

Libraries that help with JS inheritance implement inheritance and do rely on prototype.constructor with something in the spirit the following:

function extend(base, sub) {    function surrogateCtor() {}   // Copy the prototype from the base to setup inheritance   surrogateCtor.prototype = base.prototype;   sub.prototype = new surrogateCtor();   // The constructor property is set to the base constructor   // with the above trick, let's fix it   sub.prototype.constructor = sub; } 

You can see that in the above code, we have to fix the constructor property because it's sometimes used to create instantiate an object when you only have an instance. but it doesn't affect the actual constructor. See my post about JS inheritance http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

How to redefine a constructor If you really want to redefine a constructor, just do

// If Rabbit had any custom properties on it  // (or static properties as some call it), they would not be copied, you'd have to do that manually using getOwnPropertyNames  // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames var oldProto = Rabbit.prototype; Rabbit = function() {...}; Rabbit.prototype = oldProto; 

Note that this would not affect code that had already copied that reference, for example:

const myRefRabbit = Rabbit 
like image 125
Juan Mendes Avatar answered Oct 21 '22 12:10

Juan Mendes