views:

74

answers:

3

I'm still struggling with this concept. I have two different Person objects, very simply:

;Person1 = (function() {
    function P (fname, lname) {
        P.FirstName = fname;
        P.LastName = lname;
        return P;
    }
    P.FirstName = '';
    P.LastName = '';
    var prName = 'private';
    P.showPrivate = function() { alert(prName); };
    return P;
})();

;Person2 = (function() {
    var prName = 'private';
    this.FirstName = '';
    this.LastName = ''; 
    this.showPrivate = function() { alert(prName); };
    return function(fname, lname) {
        this.FirstName = fname;
        this.LastName = lname;
    }   
})();

And let's say I invoke them like this:

var s = new Array();

//Person1
s.push(new Person1("sal", "smith"));
s.push(new Person1("bill", "wonk"));
alert(s[0].FirstName);
alert(s[1].FirstName);
s[1].showPrivate();

//Person2
s.push(new Person2("sal", "smith"));
s.push(new Person2("bill", "wonk"));
alert(s[2].FirstName);
alert(s[3].FirstName);
s[3].showPrivate();

The Person1 set alerts "bill" twice, then alerts "private" once -- so it recognizes the showPrivate function, but the local FirstName variable gets overwritten.

The second Person2 set alerts "sal", then "bill", but it fails when the showPrivate function is called. The new keyword here works as I'd expect, but showPrivate (which I thought was a publicly exposed function within the closure) is apparently not public.

How can I ensure that my closure is a reusable object with publicly exposed methods? I am using the (function() { //object code })(); syntax to ensure my variables are scoped only to the object being created. Thanks!

A: 

You want to be using the prototype method of creating Person objects.

;(function(){
    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;

        function showPrivate() {
            alert(this.firstName);
        }
    }

    Person.prototype.getName = function() {
        return this.firstName + ' ' + this.lastName;
    }

})();    

showPrivate will be private as it's creating inside the constructor. The getName function is public, and can be invoked from outside the Person object.

I'm not entirely sure what you're trying to accomplish here. Your question is a little confusing. Perhaps try to reword?

steve_c
Thanks for your advice -- I clarified the question, maybe it makes more sense? I'm trying to use the (function() { //object code })(); syntax to ensure my variables remain locally scoped.
TimDog
How would you roll your above example into an immediately-executed closure? So it's all contained within a (function() { //your code here })(); block?
TimDog
See my edits above.
steve_c
A: 

I modified Person2 to declare the showPrivate function within the constructor -- ensuring the function was public:

;Person2 = (function() {
    var prName = 'private';
    return function(fname, lname) {
        this.FirstName = fname;
        this.LastName = lname;
        this.showPrivate = function() { alert(prName); };
    }
})();
TimDog
+2  A: 

this is using the technique from "JavaScript: The Good Parts" by Douglas Crockford http://oreilly.com/catalog/9780596517748

Chapter 5: Inheritance - section 'Functional'

var personConstructor = function (spec) {
    var that = {};

    that.fullName = function () {
            return spec.first_name + " " + spec.last_name;
    };

    that.setFirstName = function (firstName) {
            spec.first_name = firstName;
    };

    return that;
};

var john = personConstructor({first_name: "John", last_name: "Doe"});
var jane = personConstructor({first_name: "Jane", last_name: "Doe"}); 

alert(john.fullName()); // John Doe
alert(jane.fullName()); // Jane Doe

john.first_name = "OVERWRITE";
alert(john.fullName()); // John Doe

john.setFirstName("OVERWRITE-VIA-SETTER");
alert(john.fullName()); // OVERWRITE-VIA-SETTER Doe

put this together on jsfiddle, link below if you want to test drive it, watch out for the 4 alerts when the page loads

http://jsfiddle.net/SecKg/

house9