1

I am learning how to implement OOP in JavaScript using constructor functions, and I am facing some confusion regarding how sub types are created.

My current understanding is, the new keyword is what works behind the scenes to do the following:

  • create an empty this object
  • set the __proto__ property of the this object to point to the prototype property on the constructor function
  • return the this object

That is why we do not have to explicitly return an object from our constructor function, the new keyword does it for us.

In the example below I am creating a PaidUser sub type of the User type:

function User(name) {
  this.name = name;
}

function PaidUser(name, balance) {
  User.call(this, name);
  this.balance = balance;
}

Following examples I have seen, I am extending from the User types properties in the PaidUser type and setting the context of this in the User constructor to point to the lexical this with User.call(this,...)

My confusion is regarding how does User.call() affect what is implicitly returned by the new keyword from the PaidUser constructor?

For example in the PaidUser constructor i define the this.balance property to the this object, now it is my understanding it is the this object which will be returned from the PaidUser constructor, when called with the new keyword. How does User.call(this, name) ever get returned or effect the object returned from the PaidUser constructor.

Currently according to my understanding, this is what imagine is sort of happening behind the scenes:


function PaidUser(name, balance) {
  this = {
  __proto__:PaidUser.prototype
  };
  this.balance = balance;
  User.call(this, name); // {this.name:name}; //lexical this
                         // why is the object returned from User.call() just floating around
                         // neither assigned to a variable or returned ?

  return this;  // how does this.name ever become part of the returned object?
}

I would really appreciate any help and explanation regarding the steps taken by the new keyword when when the PaidUser constructor function is called.

With much thanks and appreciation.

4
  • User.call(this, name) explicitly makes this in the User() function be the same this that the new call to PaidUser created. Commented Oct 10, 2019 at 18:25
  • I think I understand, when we call User.call(this,name) it calls the User function and sets the name property on the PaidUser this object? I guess i got lost in all the constructor creation specifics and forgot to remember we are infact calling a function with User.call() Thankyou very much! Commented Oct 10, 2019 at 18:34
  • call can create multiple objects with the same scope. Commented Oct 10, 2019 at 18:41
  • The new keyword basically does this: function customNew(Constructor, ...args) { const obj = Object.create(Constructor.prototype); const result = Constructor.apply(obj, args); return result && typeof result === 'object' ? result : obj;) Commented Oct 10, 2019 at 18:42

1 Answer 1

1

My confusion is regarding how does User.call() affect what is implicitly returned by the new keyword from the PaidUser constructor?

The key to understanding how that happens is understanding that objects that are passed into a function can be affected outside of it:

//function that takes an object and mutates it
function fn(o) {
  o.hello = "universe";
}

//a simple object
var obj = {
  hello: "world"
};

console.log("before calling the function", obj);

//call the function with the object
fn(obj);

console.log("after calling the function", obj);

So, objects can be mutated inside functions and it affects them outside the function, too.

This is also what happens when you invoke User.call(this, name); the body of the User constructor function is this.name = name which mutates the this context. Since the this context is an object, it will be mutated outside of the function. And since it mutates the this context of new PaidUser effectively the code does this:

function PaidUser(name, balance) {
  this.name = name; //contents of User.call(this, name);
  this.balance = balance;
}

So, it's actually a lot less magical than it seems. The only part the new keyword plays in the entire process is that new PaidUser will create a new object and set it as the this context. You can emulate a similar effect by doing the following:

function User(name) {
  this.name = name;
}

function PaidUser(name, balance) {
  User.call(this, name);
  this.balance = balance;
}

var obj = {};

PaidUser.call(obj, "Fred", 1234);

console.log(obj);

This doesn't do everything the new keyword does - it won't set the prototype, not make the constructor function implicitly return this, but it still creates a new object and puts it through all the assignments. Since we have reference to the object, we can examine it afterwards and see that indeed the code has effectively done obj.name = name and obj.balance = balance.

Sign up to request clarification or add additional context in comments.

2 Comments

Basically what I wanted to write. I would add that objects are reference type values (and mutable) which is why mutating them inside a function affects them outside the function. There are languages where that is not the case (e.g. PHP arrays). Also see my comment on the question for a user space new function.
@VLAZ I understand perfectly now, thank you for the detailed explanation, it has really reinforced my understanding. In truth I got lost in the specifics of the new keyword, and as you mentioned, made it to be more 'magical' than it is. And failed to realize we are just mutating the this object by calling User.call(this,name) --Many thanks for your help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.