Reputation: 271
I'm trying to figure out if (other than the obvious fact that in one case the value the of following constructor function is set to the name of a function outside of the constructors braces and in the other case the value is set directly to the function itself, inside the function) these two codes are any different in any significant way.
function people(name, age){
this.name = name;
this.age = age;
this.yearsUntilRetire = yearsLeft;
}
function yearsLeft(){
var numYears = 65 - this.age;
return numYears;
}
var natalie = new people("Natalie Portman", 28);
var joony = new people("Joony Boony", 24);
and...this code?
function people(name, age){
this.name = name;
this.age = age;
this.yearsUntilRetire = function(){
var numYears = 65 - this.age;
return numYears;
}
}
var natalie = new people("Natalie Portman", 28);
var joony = new people("Joony Boony", 24);
Now, I've noticed that both codes work, for my purposes, exactly the same. I just wanted to know if there is any difference between the two codes or if they are, exactly the same. I prefer the tighter code, where the function is nested inside of the constructor rather than all loose outside of the function, but I've seen several tutorials that set the value to a function outside of the constructor function (as in the first example). This is kind of puzzling to me because it seems more logical to create a blueprint for an object all in one self contained space rather than all over the place where you have to scan up and down to find what this refers to, and where.
I guess my ultimate question is whether one way is right and the other is wrong, or whether one has advantages and the other doesn't. Is there a "normal" way to do this or is it just a free for all and the programmer should just do whatever they want?
Upvotes: 0
Views: 66
Reputation: 169018
The second example will create a new function object for each separate object (if an implementation optimizes this away they are making a serious mistake) while the first example pollutes the global namespace with a function.
Aside from Felix's approach of using the prototype (+1 to him), you can also use an immediately-executed closure to hide the function:
var people = (function () {
function yearsLeft(){
var numYears = 65 - this.age;
return numYears;
}
return function (name, age) {
this.name = name;
this.age = age;
this.yearsUntilRetire = yearsLeft;
}
}());
The function object returned from the outer function gets assigned to the people
variable, and it has access to the yearsLeft
function defined in the outer function. Code outside of this function has no access to yearsLeft
(except, of course, through the yearsUntilRetire
property of objects created from this function).
While this may not be the best approach for this particular problem (prototypes are a bit cleaner in this case) this technique of immediately-invoking a function that returns another function is a very powerful way to create a function that depends on private data.
Upvotes: 1
Reputation: 816442
The differences are:
yearsLeft
doesn't have access to local variables defined inside people
. In the second case it does.person
.person
will create a new inner function. I.e. for two instances of person
, p1.yearsLeft === p2.yearsLeft
will be false
which might be surprising.The correct way is to define shared properties on the prototype:
function People(name, age){
this.name = name;
this.age = age;
}
People.prototype.yearsLeft = function() {
var numYears = 65 - this.age;
return numYears;
};
If you want to learn more about OOP in JavaScript, I recommend to read the MDN article about it.
Upvotes: 2