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;
}());
精彩评论