Function variable added to global scope
I have declared a function:
function makePerson() {
this.first = 'John';
this.last = 'Oliver';
fullName = function(){
return this.first + this.last;
}
}
Didn't instantiate but did call this function.
makePerson()
I can now access first
, last
and fullName
globally.
Can someone explain to me why this is happening.
Note. Instead of calling it, I created it and tested it. It is not global and is available within the scope of functions / class / object.
This is the normal semantics of a keyword this
in a function. this
can be evaluated in several ways, depending on how you call this function. Let's say we have a function f
where the body contains a keyword this
:
- B
f(a,b)
(standard function syntax) isthis
tied to global JavaScriptObject
, which means that if you add in properties inthis
the body of a function, you will actually add them to the global scope. - The
anObject.f(a,b)
(method call syntax) isthis
bound toanObject
. - B
new f(a,b)
(constructor call syntax) isthis
bound to the object being constructed.
this
can be a source of confusion, and once the function body contains this
, the function is no longer first-class. For this reason, I recommend that you do not use this
as much as you can, like Douglas Crockford .
If you want to make a factory function (which I highly recommend for the above reason), you can do it like this:
function makePerson() {
var person = {
first: 'John',
last: 'Oliver'
};
person.fullName = function(){
return person.first + person.last;
};
return person;
}
If you still want to create a constructor, the convention requires the name to be capitalized:
function Person() {
this.first = 'John';
this.last = 'Oliver';
this.fullName = function(){
return this.first + this.last;
};
}
Finally, there may be good reasons for using a keyword this
, and that is prototypical inheritance. However, I find the constructor syntax to be misleading. Fortunately, we now Object.create
:
var personPrototype = {
fullName: function () {
return this.first + this.last;
}
};
function makePerson(first,last) {
var person = Object.create(personPrototype);
person.first = first;
person.last = last;
return person;
}
As a final warning, here's an example of how usage this
can lead to unexpected restrictions and confusion:
var cn = makePerson("Chuck","Norris");
// works fine
console.log(cn.fullName());
// does not work, fullName is not a first-class function. You cannot detach it.
var fullName = cn.fullName;
console.log(fullName());