Given the following:
function MyClass() {
this.name = "Agnus"
return function() {
console.log(this.name)
}
}
const user = new MyClass() //this = "MyClass"
const r = MyClass() //this = "window"
console.log(name) //Agnus, this = "window"
r() //Agnus, this = "window"
My expectation was that on calling r(), I will get a error as the value of "this" is window for its case but instead it returned me "Agnus". On checking, I found that the properties of the object constructor MyClass are available from global.
I am having little difficulty to wrap my mind around such behavior, so it will be really nice if someone can explain me a bit about this.
Thank you for your help.
CodePudding user response:
When you use new
, you set the this
to a new empty object whose internal prototype is the constructor's .prototype
. That is:
new MyClass()
function MyClass() {
// `this` is now equivalent to Object.create(MyClass.prototype)
But if you explicitly return an object from a constructor function, the this
will essentially be discarded, and the returned object will be used instead. Here, the returned object is the function, and the
this.name = "Agnus"
line assigns to an object which is never referenced again.
In contrast, when you don't use new
, and the function you call isn't a property of an object (or bound, or an arrow function), this
will be either the global object (in sloppy mode), or undefined
(in strict mode). In sloppy mode,
function MyClass () {
this.name = "Agnus"
does
window.name = "Agnus";
And then when you invoke the returned function later with r()
, since it's not a property of an object, its this
is the global object - whose name
is Angus
.
To reduce confusion, I recommend
- Avoiding returning objects explicitly from constructors
- Always using
new
when invoking a constructor
You don't have to, but if you do that, you'll confuse yourself (and other readers of the code) less.
Strict mode is a good idea too.