Question

I'm learning to define 'class like' function on JavaScript using the prototype property. When I'm defining a People class like so, everything is working great:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    this.fullName = function(){
        console.log(full_name);
        return this;
    };

    // private
    var self = this;
    var full_name = function(){
        return self.firstName + ' ' + self.lastName;
    }();
};

var person = new People('John', 'Smith');
person.fullName();  // => "John Smith"

However, when I'm moving the fullName method outside of the initial definition like so:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    // private
    var self = this;
    var full_name = function(){
        return self.firstName + ' ' + self.lastName;
    }();
};

People.prototype.fullName = function(){
    console.log(full_name);
    return this;
};

var person = new People('John', 'Smith');
person.fullName();  // => "ReferenceError: full_name is not defined"

I'm getting an error. I can't understand why...??

Was it helpful?

Solution 2

Pointy is using the wrong pattern for private shared members, the pattern is for private instance specific members and every instance will have it's own addressMe function.

The pattern for private shared members could wrap the prototype in an IIFE:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;
};

(function(){
  // private shared member
  var full_name = function(){
      return this.firstName + ' ' + this.lastName;
  };
  //privileged member that has access to private shared
  //  fullName is a closure and full_name is available
  //  in the colosure scope created for this function
  People.prototype.fullName = function(){
    //calling private member, make sure you set
    //  the invoking object (this) by using
    //  Function.prototype.call
    console.log(full_name.call(this));
    return this;
  };
}());

var person = new People('John', 'Smith');
person.fullName();

You can't use this pattern for instance specific private members but the function full_name is not instance specific.

A pattern for protected and more info on prototype and constructor functions can be found here.

OTHER TIPS

Here:

var full_name = function(){
    return self.firstName + ' ' + self.lastName;
}();

you're setting the variable "full_name" to be the result of calling that anonymous function. It's just a variable declared in the context of that constructor, however, so that doesn't really matter; nothing outside of the constructor can access it.

Thus in that prototype function, you get an error because "full_name" is in fact not defined. If you want the full name function on the prototype, just declare it there:

People.prototype.fullName = function() {
  return this.firstName + " " + this.lastName;
};

If you want a "private" function that accessible only to code in the constructor, then you'd do something like this:

var People = function(firstName, lastName){
    // public
    this.firstName = firstName;
    this.lastName  = lastName;

    // private
    var self = this;
    function fullName(){
        return self.firstName + ' ' + self.lastName;
    }

    this.addressMe = function(msg) {
        return fullName() + ": " + msg;
    };
};

Then you can do:

var bob = new People("Bob", "Scum");
alert( bob.addressMe("stand and deliver") ); // "Bob Scum: stand and deliver"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top