1

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...??

5
  • 2
    There are no classes or private, it's functions and scope, but some smartypants decided to call it "classes" and "private / public" (It was probably Crockford, lets blame him). Commented May 1, 2014 at 21:52
  • It's not clear what you want. If you want "full_name" to be a function visible as a property of the prototype, then there's no reason for it to be "private". Commented May 1, 2014 at 21:52
  • @adeneo You're right... that's why I called it "class like" lol Commented May 1, 2014 at 22:13
  • 1
    see also Javascript: Do I need to put this.var for every variable in an object? Commented May 1, 2014 at 22:16
  • @Bergi Nicely explained but it's not what I asked here. Commented May 1, 2014 at 22:42

2 Answers 2

3

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"
Sign up to request clarification or add additional context in comments.

2 Comments

you're using the wrong pattern for private shared members. The pattern you're using is for private instance specific (unique for every instance). Since full_name is a function and can be shared you don't have to ditch prototype to implement it.
@HMR I agree; I wouldn't code up anything like this, probably. The intentions of the original question are not really clear.
1

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.

2 Comments

Thx for ur answer but much more for the link you attached in the end of it. Great explanation there!!! Do you share a blog of ur own as well?
@Lior Thank you, don't have a blog. Think JavaScript prototype is one of the most misunderstood things in programming and wrote that while trying to figure it out myself. SO is perfect for that as I hope comments will point out mistakes or suggest improvements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.