views:

75

answers:

2

I have begun writing my 'class' type JavaScript functions like the Module Pattern or Revealing Module patten. This avoids the use of 'new' and allows me to define which functions are public in a single place. However, I have been unable to see how to use and access public data members in this pattern.

e.g. the member 'id' below is accessible through myobj.getId(), but myobj.id is undefined.

function setup(){
    var myobj = MyObject();
    myobj.initialize();
    alert(myobj.getId()); // returns 3, as expected
    alert(myobj.id); // returns undefined
}
function MyObject(){
    var id;
    function initialize(){
        //do some stuff that initializes data including...
        id = 3;
    }
    return{
        initialize:initialize,
        id:id,
        getId:function(){ return id;}
    }
}

Is there no way to get myobj.id to work returning the value that was set in initialize()?

+1  A: 

The reason is that your variable id is set to undefined by default and it's type will be undefined as well. Now, because undefined type is a primitive one your assignment in the returned object will be a value assignment, not reference. So obj.id will become undefined in the instance and not the same as the id variable in the constructor function.

Now initialize will change the id in the constructor function, and getId will return the same id, but obj.id will refer to the undefined object property.

function MyObject(){
    // initialize is used as a public function so
    // this will always refer to the current instance
    function initialize(){
        this.id = 3;
    }
    return {
        // no need to define id here it will 
        // report undefined on access by default
        initialize: initialize,
        getId:function(){ return this.id; }
    }
}

Run the whole stuff to see it works as expected. ​

galambalazs
No need for all of the attitude you've shown in the deleted response, but I believe you've answered my question.
pc1oad1etter
my responses were about not to confuse you more. :) When someone sticks to his misconceptions and even spreads it, what would you do? I tried to outline the problems but he didn't listen. As you can see he finally realized and deleted his answer. No hard feelings, again, it's all about correctness, and not to confuse people.
galambalazs
+2  A: 

Your problem is that you aren't taking advantage of closure. The line id:id creates a new variable as a member of the object literal you are returning. This has the default value undefined. Then you are assigning the same variable id back to itself, undefined again.

Also, a module is a single object instance, not a factory function. Try something like this:

var myModule = (function(opts) {
    var foo = opts.foo || 0,    //private variables with default values
        bar = opts.bar || 0,    // if none are passed in

        product = function() {      //private method
            return (foo * bar);
        };

    return {
        getFoo : function() {   //public methods
            return foo;
        },
        fooTimesBar : function() {
            return product();
        }
    }
})({
    foo : 5,                    //options object
    bar : 7
});

The core of the module pattern is a self executing anonymous function that declares variables and then returns an object that has privileged access to those variables through closure.

The extra parens at the end, here containing an object literal with some options that get passed in, executes the function, which then returns an object and assigns it to myModule.

Anything declared as a member of that returned object can be accessed publicly. Code in the returned object has access to the variables defined in the anonymous function through closure even after the function has returned. The variables declared in the anonymous function are effectively private. Code outside the function cannot address them except through the methods provided in the returned object.

The whole thing results in a single object instance in myObject. No more than one can be created, which is the definition of a module. A similar approach could be taken the create a factory function however.

jasongetsdown
+1 Nice example and explanation
Josh Stodola
@jasongetsdown - I realized that this is not a singleton module, but I don't really know what word there is to describe this pattern of returning an object literal at the end - mostly I have seen it used in descriptions of the module pattern.
pc1oad1etter
@jasongetsdownI may not have expressed it clearly, but when I said "I have begun writing my 'class' type JavaScript functions like the Module Pattern or Revealing Module patten" I meant that I would be using the style of returning an object at the end -- like what I have seen in the Module and Revealing Module pattern.So, I'm not actually looking for a Module at all like you described. I have used it as a Module, and I liked this aspect of it so much that I wanted to use it like a constructor, which is what led me to this question. Thanks.
pc1oad1etter
I would call it a factory function. If you modified my example to be `myFactory = function(opts) {...}` instead of `myModule = (function(opts) {...})()` then that is exactly what you would have. `myFactory` would be a function that returned a new instance each time it was run, instead of `myModule` which is a singleton instance.
jasongetsdown
Thanks! should your 'product' method have a var in front of it? Would that potentially use a global 'product' ?
pc1oad1etter
it is part of the initial `var`. Note the comma after the declaration of `bar`. Perhaps a little confusing because of the indentation, but my intention was to show that you can essentially write all the private members as one long `var` statement. I should have added a semicolon to terminate the `var` after the closing bracket of `product`. Editing for clarity...
jasongetsdown