Allan Socks
Allan Socks

Reputation: 271

Can I set a property to be equal to a function inside the body of a constructor function?

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

Answers (2)

cdhowie
cdhowie

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

Felix Kling
Felix Kling

Reputation: 816442

The differences are:

  • Scope: In the first case, yearsLeft doesn't have access to local variables defined inside people. In the second case it does.
  • Visibility: In the first case the function is defined and accessible outside of person.
  • Memory: In the second case, every invocation of 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

Related Questions