开发者

When returning an object from a JavaScript constructor function (avoiding 'new') how do I implement public members?

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 = 开发者_JAVA技巧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()?


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.


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


You can solve this and still maintain the syntactic sugar of the Revealing module pattern by returning a cached object instead of an anonymous one.

eg:

NAMESPACE.Module = (function () {

    //All public members go on api
    var api = {}
    api.id = 3;

    //Private members
    var self,
        foo,
        bar;


    /**
        @public
    */
    api.init = function () {
        self = this;
        console.log(this); //NAMESPACE.Module
    }


    /**
        @private
    */
    function _privateFunction() {
        console.log(self); //NAMESPACE.Module
    }

    return api;
}());
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜