I've been writing an application and I have had a lot of success breaking different pieces of functionality into the so called "Module" pattern where you have a self-executing singleton with public and private members.
var WidgetModule = (function($, options) {
// Private variable
var someVar;
// Private functions
function somePrivateFunction() {
}
// Define the public members
var self = {
init: function() {
},
someFunction: function() {
}
};
return self;
})(jQuery, options);
I have now run into a case where I have several modules which I would like to be able to create multiple instances of.
I know this pattern is based on the singleton but I wonder if there was a painless way to modify this pattern to support creating instances of them?
When I need common functionality for multiple objects, here's the pattern I usually use (adjusted to account for the code you presented):
var Widget = (function($) {
var pubs = Widget.prototype;
// Private variable -- global to all instances
var someVar;
// The constructor
function Widget(options) {
var privateInstanceVar;
this.privateInstanceFunc = function() {
return privateInstanceVar;
};
}
// Private functions -- global to all instances
function somePrivateFunction() {
}
// Define the public members
pubs.init = function() {
};
pubs.someFunction = function() {
};
return Widget;
})(jQuery);
Usage:
var w = new Widget({someOption: "here"});
As you can see, you can share private data amongst all instances created by the constructor, and if you really want to, you can have private data that's shared only with certain select instance functions. Those functions have to be created in the constructor, which has reuse implications, whereas functions that don't need the truly-private instance data can be on the prototype and therefore be shared by all instances.
Better yet, since you already have a handy scoping function, you can help your tools help you by giving your public functions actual names:
pubs.init = Widget_init;
function Widget_init() {
}
I mostly don't actually code the above, because I've defined a helper factory that makes it a bit more concise (and makes it easier to do specializations of functionality, like a Car inheriting functionality from Vehicle); details here.
What about this:
function WidgetModule(options){
//var $ = jQuery;
// Private variable
var someVar;
// Private functions
function somePrivateFunction() {
}
// Define the public members
var self = {
init: function() {
console.log(options.id);
},
someFunction: function() {
}
};
return self;
}
var w1 = WidgetModule({id:1}),
w2 = WidgetModule({id:2});
w1.init(); // --> 1
w2.init(); // --> 2
Related
I'm currently making a tiny game structured like so:
let Game = function() {
let privateVar;
// private would be an example private variable assigned later
// Other private variables go here
return {
Engine: function() {
// More specific private variables
init: function() {
privateVar = this.sampleValue;
// Game.Engine.sampleValue doesn't help either
// Start up everything, for example, calling a Graphics method:
Game.Graphics.method1();
},
sampleValue: 10,
// Other methods
}
Graphics: Graphics()
}
}
function Graphics() {
// Visuals-specific private variables
return {
method1: function() {
console.log(privateVar);
// This would complain about the variable not being defined
}
// methods
}
}
Game.Engine.Init();
The idea is to separate the visual code from the internal code by calling the Graphics() function in the Graphics method (so I can for example build the Graphics() function in a separate file for example). However, when I do this, the Graphics method loses the private variable I declared at the beginning and assigned at the init method, and spits out Uncaught ReferenceError: private is not defined whenever it's called by some method in Graphics.
I guess one solution would be just reassigning those privates in Graphics(), but that would somewhat kill the purpose. Anyone has a better idea? Thanks in advance.
EDIT: Made the code a bit easier to understand what I'm getting at
If you want private variables your Graphics type should not access them. How about declaring public variables instead ?
Like this for instance:
let Game = function() {
this.publicVar = "value";
}
Or you can declare getters to access private fields and pass Game instance to the Graphics type. Like this :
let Game = function() {
let privateVar = "value";
this.getPrivateVar = function() {
return privateVar;
}
}
function Graphics(game) {
// ...
}
I think that you are trying to use O.O. in javascript.
Javascript is prototyped, so, the way you will use O.O. is different than usual languages. see mozilla reference
I think you should create js classes like these:
/**
* #class Game Class
*/
function Game() {
this.privateProperty;
this.engine = new Engine(); //engine object of this game
this.graphics = new Graphics(); //graphics object of this game
}
Game.prototype.oneGameMethod = function(){
};
/**
* #class Engine Class
*/
function Engine(){
this.privateProperty;
}
Engine.prototype.oneEngineMethod = function(){
};
/**
* #class Graphics class
*/
function Graphics() {
// Visuals-specific private variables
this.visualProperty;
}
Graphics.prototype.oneMethodExample = function(){
};
Than you can create an Game object and call its methods and so on:
var myGame = new Game();
I'm working with a pattern that looks like so (pseudo example):
var FOO = (function(foo) {
var foo = foo || {},
setThis = 'someValue';
//--------------------------------------------------------------------------
//
// Public methods:
//
//--------------------------------------------------------------------------
foo.init = function(bar) {
this.blah = [];
// Constructor stuff here...
};
foo.doSomething = function(bar) {
if (bar) {
this.doSomethingElse();
// Stuff here...
}
};
foo.doSomethingElse = function() {
// Stuff here...
};
//--------------------------------------------------------------------------
//
// Private methods:
//
//--------------------------------------------------------------------------
foo._imPrivate = function() {
// ... stuff here ...
this.blah = xyz; // References this.
};
foo._morePrivate = function(el) {
// No reference to this.
};
foo._otherPrivate = function(el) {
// No reference to this.
};
return foo; // Expose the methods.
}(FOO || {}));
Instanciated like so:
window.onload = function() { FOO.init(stuff); }
Three questions:
If my "private" methods don't reference this, should I just make them "standard" functions (i.e. function _imPrivate() { ... }, for example)? Reason why I ask: I have a few methods that reference this, but I don't want to give them public access; I also have a few "utility" methods that don't reference this... Can the methods that reference this be standard functions (in context of the module pattern)?
Could someone provide an example of how I would implement a setter for the setThis variable?
Do you see any room for improvements in the above code?
The "private" methods aren't private at all, they're public. The OP doesn't seem to take any advantage of closures available from the use of an immediately invoked function expression (IIFE).
The value of a function's this is set by how you call a function, it isn't static (unless you use ES5 bind). It has nothing to do with "context" (at least not in the way context is used in ECMA-262, which is how the word should be used in the context of javascript).
Douglas Crockford's Private Members in JavaScript will help.
If you post a real example of what you are trying to do, you will likely get more help on how to exploit the module pattern in its implementation.
1.
You can do _imPrivate.call(this, arg1, arg2,...);
And in this case this in the _imPrivate function will refer to the particular instance.
2.
var setThis = 'someValue';
foo.setter = function(value) {
setThis = value;
};
I have a class similar to the one below. How do I call my init method when the object is created? I don't want to have to create an instance of my object then call initialize like I do below.
var myObj = new myClass(2, true);
myObj.init();
function myClass(v1, v2)
{
// public vars
this.var1 = v1;
// private vars
var2 = v2;
// pub methods
this.init = function() {
// do some stuff
};
// private methods
someMethod = function() {
// do some private stuff
};
}
NB. Constructor function names should start with a capital letter to distinguish them from ordinary functions, e.g. MyClass instead of myClass.
Either you can call init from your constructor function:
var myObj = new MyClass(2, true);
function MyClass(v1, v2)
{
// ...
// pub methods
this.init = function() {
// do some stuff
};
// ...
this.init(); // <------------ added this
}
Or more simply you could just copy the body of the init function to the end of the constructor function. No need to actually have an init function at all if it's only called once.
There is even more smooth way to do this:
this.init = function(){
// method body
}();
This will both create method and call it.
See below for one possible answer, and some corrections to your code.
function myClass(v1, v2)
{
// public vars
this.var1 = v1;
// private vars
// use var to actually make this private
var var2 = v2;
// pub methods
this.init = function() {
// do some stuff
};
// private methods
// this will be private as though it had been declared with var
function someMethod() {
// do some private stuff
};
//call init
this.init();
}
JavaScript classes introduced in ECMAScript 2015 are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JavaScript classes provide a much simpler and clearer syntax to create objects and deal with inheritance.
- MDN web docs
When using this syntax, because only the constructor() method is run on instantiation you can't auto-instantiate an object. You always have to add user = new MyUser()
var user;
class MyUser {
constructor(var1, var2) {
this.var1 = var1;
this.var2 = var2;
}
static staticMethod() {
// accessed directly with the class name `MyUser`
}
instanceMethod() {
// accessed with object instance
return true
}
}
user = new MyUser('hey','there')
Just add
this.init();
to your myClass function.
I'm not entirely sure how to implement OOP concepts in JS.
I have a class which is entirely declared in its constructor:
function AjaxList(settings)
{
// all these vars are of dubious necessity... could probably just use `settings` directly
var _jq_choice_selector = settings['choice_selector'];
var _jq_chosen_list = settings['chosen_list'];
var _cb_onRefresh = settings['on_refresh'];
var _url_all_choices = settings['url_choices'];
var _url_chosen = settings['url_chosen'];
var _url_delete_format = settings['url_delete_format'];
var jq_choice_selector_form = _jq_choice_selector.closest("form");
if (DEBUG && jq_choice_selector_form.length != 1)
{
throw("There was an error selecting the form for the choice selector.");
}
function refresh()
{
_updateChoicesSelector();
_updateChosenList();
_cb_onRefresh();
};
AjaxList.prototype.refresh = refresh; // will this be called on all AjaxLists, or just the instance used to call it?
// AjaxList.refresh = refresh; // will this be called on all AjaxLists, or just the instance used to call it?
// ...
}
There are multiple instances of AjaxList. When I call refresh() on one of them, I want only that one list to refresh itself. In the following instance:
term_list = AjaxList(settings);
term_list.refresh();
The refresh() call seems to make all the AjaxLists refresh themselves. What is the correct way to do this?
I'm using jQuery, if it makes any difference.
You should not redefine the prototype function in the constructor.
If you want to create a privileged function use this.methodname = ... from the constructor.
function AjaxList() {
var privateVar = 0;
function privateFunction() {
//...
}
//create a refresh function just for this instance of the AjaxList
this.refresh = function() {
//privileged function, it can access the 'privateVar & privateFunction'
privateVar++;
}
}
//public functions that don't need access to the private variables/functions
AjaxList.prototype.publicFunction=function() {
};
Also if you want to create a proper object, you need to change
term_list = AjaxList(settings);
to
term_list = new AjaxList(settings);
AjaxList = function(settings) {
this._jq_choice_selector = settings["choice_selector"];
this._jq_chosen_list = settings["chosen_list"];
this._cb_onRefresh = settings["on_refresh"];
this._url_all_choices = settings["url_choices"];
this._url_chosen = settings["url_chosen"];
this._url_delete_format = settings["url_delete_format"];
this.jq_choice_selector_form = _jq_choice_selector.closest("form");
if (DEBUG && jq_choice_selector_form.length != 1) {
throw "There was an error selecting the form for the choice selector.";
}
};
AjaxList.prototype = {
_updateChoicesSelector: function() { },
_updateChosenList: function() { },
_cb_onRefresh: function() { },
refresh: function() {
this._updateChoicesSelector();
this._updateChosenList();
this._cb_onRefresh();
}
};
Given that structure, you should be able to call:
var ajaxList = new AjaxList(settings);
ajaxList.refresh(); // etc.
I'm using jQuery, if it makes any
difference.
No it doesn't. See my answer here: What's the difference between Javascript, Jquery and Ajax?
I have a class which is entirely
declared in its constructor
There are no classes in Javascript. Forget them. You really need to learn some of the basics of this language in order to use them. It's not Java, even though it looks similar.
If you have a Constructor Function it will create an instance. The shared methods will be in the prototype chain, and only instance specific data goes right into the function with the this keyword.
So the basic concept of an object would look like this:
// constructor of an instance
function MyObject( param1, param2 ) {
this.param1 = param1;
this.param2 = param2;
this.param3 = 32;
return this; // [optional]
}
// Public methods can be called by any instance.
// Instances share their prototype object.
// The this keyword always points to the current
// instance that calls the method.
MyObject.prototype.sum = function() {
return this.param1 + this.param2 + this.param3;
}
// refresh should be a shared method, since it
// does the same thing on every instance
MyObject.prototype.refresh = function() {
// do the refresh
// ...
}
The power of this concept is that there is only one refresh function in memory. And it can deal with any instance. In addition, if another object inherits from MyObject the refresh function will be inherited. But in the memory there will be still one shared refresh function. And it can deal with any of the parent or child instances.
How can I create a function that can't be called from outside?
var obj = {
function1: function(){
alert("function1");
},
function2: function(){
alert("function2...");
obj.function1();
}
};
// so how to make this function unaccessible
obj.function1();
// and you could only call this function
obj.function2();
You may want to consider using the Yahoo Module Pattern. This is a singleton pattern, and the methods are not really static, but it may be what you are looking for:
var obj = (function () {
//"private" variables:
var myPrivateVar = "I can be accessed only from within obj.";
//"private" method:
var myPrivateMethod = function () {
console.log("I can be accessed only from within obj");
};
return {
myPublicVar: "I'm accessible as obj.myPublicVar",
myPublicMethod: function () {
console.log("I'm accessible as obj.myPublicMethod");
//Within obj, I can access "private" vars and methods:
console.log(myPrivateVar);
console.log(myPrivateMethod());
}
};
})();
You define your private members where myPrivateVar and myPrivateMethod are defined, and your public members where myPublicVar and myPublicMethod are defined.
You can simply access the public methods and properties as follows:
obj.myPublicMethod(); // Works
obj.myPublicVar; // Works
obj.myPrivateMethod(); // Doesn't work - private
obj.myPrivateVar; // Doesn't work - private
The simple answer is that you can't do both. You can create "private" methods or "static" methods, but you can't create Private static functions as in other languages.
The way you can emulate privacy is closure:
function f() {
function inner(){}
return {
publicFn: function() {},
publicFn2: function() {}
}
}
Here because of closure, the inner function will be created every time you call f, and the public functions can acces this inner function, but for the outside world inner will be hidden.
The way you create static methods of an object is simple:
function f() {}
f.staticVar = 5;
f.staticFn = function() {};
// or
f.prototype.staticFn = function() {};
Here the function object f will only have one staticFn which has access to static variables, but nothing from the instances.
Please note that the prototype version will be inherited while the first one won't.
So you either make a private method that is not accessing anything from the instances, or you make a static method which you doesn't try to access from the outside.
You can use a closure, something along the lines of....
var construct = function() {
var obj = {};
var method1 = function() {
alert("method1");
}
obj.method2 = function() {
alert("method2...");
method1();
}
return obj;
}
obj = construct();
Then:
obj.method2 is accessible, but obj.method1 doesn't exist for public usage. It can be only accessed using member functions of the class.
Objects can be produced by constructors, which are functions which initialize objects. Constructors provide the features that classes provide in other languages, including static variables and methods.
Read all about it at http://www.crockford.com/javascript/private.html
You can do it like this:
var obj = new function() {
var method1 = function() { // private }
this.method2 = function() { // public }
}
obj.method1(); // not possible
obj.method2(); // possible
Note that I also use an anonymous constructor. This is sort of analogous to the Singleton pattern.
Maybe you want a proxy object containing only the public methods, e.g.
var obj = (function() {
var obj = {
method1: function(){
alert("method1");
},
method2: function(){
alert("method2...");
obj.method1();
}
}
return {
method2: function() { return obj.method2.apply(obj, arguments) }
}
})()
// you could only call this function
obj.method2();
// this function inaccessible
obj.method1();
I don't see the point of private methods in javascript. If you don't want people calling a method then don't advertise it. Private methods also make debugging just that bit harder too.
This is how it really should be done.
var MyClass = new(function() {
var privateStaticVariable = '';
function privateStaticMethod() {
}
function construct() {
var self = this;
this.publicMethod = function() {};
function privateMethod() {
//maybe lest use our private static method
privateStaticMethod();
}
}
construct.publicStaticVariable = '';
construct.publicStaticMethod = function() {};
return construct;
})();
Now lets use it:
var myClass = new MyClass();.....
MyClass.publicStaticMethod();
MyClass.publicStaticVariable = 'sfdsdf';
myClass.publicMethod();
.....
Use class. Though some of the features are still not shipped as it’s at Stage 3.
const instance = new (class Alpha {
static #private_static_method() {
console.info("I am private and static.");
}
static public_static_method() {
Alpha.#private_static_method();
console.info("I am public and static.");
}
#private_nonstatic_method() {
console.info("I am private and non-static.");
}
public_nonstatic_method() {
this.#private_nonstatic_method();
console.info("I am public and non-static.");
}
});
instance.constructor.public_static_method();
// instance.constructor.#private_static_method(); // impossible
instance.public_nonstatic_method();
// instance.#private_nonstatic_method(); // impossible