Search code examples
javascriptprototype

Setting prototype of a function as prototype of another function for doing Subclassing (with Object.setPrototypeOf()))


I'm not sure if the Title actually made any sense but however I'm trying to set a functions prototype to "sub classes" prototype.

For coming example;

What I try to do is : I have a user and paidUser . paidUser is subclass ofuser

User Factory function :

    function userCreator(name, score) {
      this.name = name;
      this.score = score;
    }
    userCreator.prototype.sayName = function(){console.log("hi");}
    userCreator.prototype.increment = function(){this.score++;}

And I can create a new user with new keyword. so far so good.

const user1 = new userCreator("Phil", 5);

Now , coming to Subclassing . (accountBalance is just a silly property special for paidUser for my example)

    function paidUserCreator(paidName, paidScore, accountBalance){
      userCreator.call(this, paidName, paidScore);
      this.accountBalance = accountBalance;
    }

now I want to set prototype of my userCreator as the prototype of paidUserCreator Factory Function

The following line works perfectly, but I don't understand it quite. Object.create function is supposed to created an empty object and that empty objects __proto__ must be the given parameter.

paidUserCreator.prototype =Object.create(userCreator.prototype);

paidUserCreator.prototype.increaseBalance = function(){
  this.accountBalance++;
}

Another point what I don't understand is :

Why the following line doesn't work ?

Object.setPrototypeOf(paidUserCreator, userCreator.prototype);

For completion :

const paidUser1 = new paidUserCreator("Katarina", 4, 12);

PS: Yes I know the Class keyword is much cleaner and nicer to read but I want to learn how to do it in this way.


Solution

  • Starting with the last question:

    Why the following line doesn't work ?

    Object.setPrototypeOf(paidUserCreator, userCreator.prototype);
    

    It will, but you need to set the prototype of paidUserCreator.prototype not the function paidUserCreator so that when an instance looks for something on the paidUserCreator.prototype and doesn't find it, it will look to userCreator.prototype.

    function userCreator(name, score) {
      this.name = name;
    }
    userCreator.prototype.sayName = function() {
      console.log("hi");
    }
    
    function paidUserCreator(paidName, paidScore, accountBalance) {
      userCreator.call(this, paidName, paidScore);
    }
    Object.setPrototypeOf(paidUserCreator.prototype, userCreator.prototype);
    
    let p = new paidUserCreator("Mark", 98, 200.5)
    p.sayName()

    paidUserCreator.prototype = Object.create(userCreator.prototype) is similar. Object.create makes a new object and sets it's prototype to point to the object passed in. When you do this you are replacing paidUserCreator.prototype with a new object that is prototype linked to userCreator.prototype. One caveat with this is that if there is anything on paidUserCreator.prototype that you need it will be lost because you are replacing the whole object, not just setting the prototype.

    Here's an example where that might bite you:

    function userCreator(name, score) {
        this.name = name;
    }
    userCreator.prototype.sayName = function(){console.log("hi");}
    
    function paidUserCreator(paidName, paidScore, accountBalance){
        userCreator.call(this, paidName, paidScore);
    }
    
    // points to the paidUserCreator function
    console.log(paidUserCreator.prototype.constructor)
    
    // replace protoype with new object
    paidUserCreator.prototype = Object.create(userCreator.prototype);
    
    // now paidUserCreator.prototype has no constructor property
    // so it defers to paidUserCreator
    console.log(paidUserCreator.prototype.constructor)