1

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!

TimDog
  • 8,758
  • 5
  • 41
  • 50
  • See http://stackoverflow.com/questions/1595611/how-to-properly-create-a-custom-object-in-javascript for background about JavaScript object systems. Don't worry about trying to really ‘hide’ private properties; there is little-to-no actual worth in this. – bobince May 26 '10 at 23:23
  • I know this comment won't be that helpful now - but I highly recommend checking out "JavaScript: The Good Parts" - http://oreilly.com/catalog/9780596517748 he really breaks down all of the different ways to create instances/objects and various approaches to inheritance and closure. This is a really short book but packed with crucial information. – house9 May 27 '10 at 15:23
  • ok, I added some code - see 'Answer' below; I am pretty sure this is what you are after? it is loosely based on your example. – house9 May 27 '10 at 15:53

4 Answers4

3

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
  • 20,359
  • 8
  • 55
  • 61
0
//this would allow for instance:
//  john.setName('first', 'Johnny');
//  jane.setName('last', 'Smith');
var personConstructor = function (spec) {
    return {
        fullName: function () {
            return spec.first_name + " " + spec.last_name;
        },
        setName: function (nameType, name) {
            spec[nameType+'_name'] = name;
        }
    };
};
PDA
  • 766
  • 6
  • 10
0

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
  • 6,235
  • 4
  • 32
  • 42
  • 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 May 26 '10 at 22:55
  • 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 May 26 '10 at 23:08
0

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
  • 8,758
  • 5
  • 41
  • 50