Why doesn't return exit this function?

This code example is meant to demonstrate a constructor that can handle the new keyword being omitted (as is the case with some built in constructors like Array)

function User(first, last) {
  if (this instanceof User === false) {
    return new User(first, last);
  }
  
  this.name = `${first} ${last}`;
}


let user1 = new User('John', 'Doe');
let user2 = User('Jane', 'Doe');

console.log(user1.name);   // => John Doe
console.log(user2.name);   // => Jane Doe

I’m guessing something about the new keyword starting a constructor invokation allows the function body to continue running operations. Can anyone break down the process to help me understand better? Thank you

Can you provide the code which calls the above User function and and explain in detail what you expect the code to do vs what it is doing?

Post updated. I’d expect that when the condition is met, meaning this is set to the global object due to the lack of new keyword during invocation of function User, a User constructor function is invoked, ending operations in the function body.

Actually this explains it. In this case, the function is simply run again, but this time the constructor is invoked properly.

A new question: Is this considered a recursive function?

I really REALLY don’t recommend writing your constructor functions that way. Any code that has to test this instanceof anything is seriously confused. this should always know what it is (at least to some lower bound anyway).

What you should be doing is adding "use strict" to the top of your JS source. When strict is enabled, this will simply be null, not the global object, and the constructor will fail as it ought to. It’s bad practice to DWIM a constructor like that, because any code calling a constructor incorrectly is broken and should be fixed at the call site. It’s likely got other bugs to worry about as well.

Oh and if you make User an ES6 class, it will automatically disallow using the constructor as a regular function, as well as enable strict within the class definition.

PS: Technically it’s recursive in the sense that it makes a recursive call for a certain edge case, but it’s not a recursive algorithm per se. And as I’ve said, it’s ill-advised to try and handle that edge case anyway.

1 Like