0

function Person(name, age, gender) {
  this.name = name; // run
}

function PersonSafe(name) {
  if (!(this instanceof arguments.callee))
    return new PersonSafe(name)

  this.name = name; // run
}

var qux = Person('qux');
console.log('Person qux: ', qux);
console.log('[[global]] name: ', name);

var quxSafe = PersonSafe('qux');
console.log('PersonSafe qux: ', quxSafe);

enter image description here

A comparison of the two situations when the constructor is called without the new keyword.

I don't know why the results of running the two codes are different.
The body ofPerson()andPersonSafe()functions are different,
but the line (this.name = name;) thatqux and quxSafe will execute is the same.
So... Why are the results different?

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
redchicken
  • 311
  • 1
  • 5
  • 18
  • https://stackoverflow.com/questions/8205691/array-vs-new-array if you are trying to find out the difference between using new and without new. – Tinu Jos K Jan 27 '20 at 09:28
  • Calling a function without `new` just executes it like any other function. `Person` doesn't contain a `return` statement, so it returns `undefined`. – JLRishe Jan 27 '20 at 09:32
  • @Tick20 Hi thanks for your comment. But, the two objects are created without `new` keyword. – redchicken Jan 27 '20 at 09:33
  • @Tick20 That's not really a good example since it's specifically about `Array`. – JLRishe Jan 27 '20 at 09:34
  • @JLRishe Hi thanks for your comment. But the line `this.name = name;` of `PersonSafe` that `quxSafe` will run is also doesn't return anything. – redchicken Jan 27 '20 at 09:36
  • 1
    @snaag `PersonSafe` contains a `return` statement. It recursively calls itself using `new` if it wasn't invoked using `new`. That's the difference. – JLRishe Jan 27 '20 at 09:38
  • 1
    @JLRishe Oh my..... Oh I was really really really dumb.... Wow.. I understand it!! Wow.. Thank you.. ha ha... – redchicken Jan 27 '20 at 09:40

2 Answers2

2

When you call a function as a constructor (here, Person), an object is created (an empty object whose internal prototype is the constructor function's prototype - Person.prototype here), and that object that was just created is what the this value will point to inside the function. That object will also be implicitly returned at the end of the constructor.

In contrast, when you don't use new, no such object is created; you're just calling an ordinary function, and the this value inside it will depend on the calling context of the function. Here, because there's no calling context (the function being called is not part of an object), the this inside the function will either be the global object (in the case of sloppy mode), or undefined (in the case of strict mode).

So var qux = Person('qux'); runs this.name = name, where this is the global object.

With PersonSafe, you're checking that the this is an instance of the constructor (that the this has an internal prototype of the constructor's prototype) - if called without new, that test will fail, since this will be either the global object or undefined.

Note that arguments.callee is forbidden in strict mode, and strict mode should nearly always be used. Consider replacing with new.target instead:

function PersonSafe(name) {
    if(!(new.target))
        return new PersonSafe(name)

    this.name = name; // run
}

var quxSafe = PersonSafe('qux');
console.log('PersonSafe qux: ',quxSafe);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

The main reason why this is different is caused by "new" keyword which means that function will be treated as object and it will get proto property assigned.

Also this variable will be pointed to newly created object.

Here is good description: What is the 'new' keyword in JavaScript?

Harion
  • 225
  • 1
  • 8