Module Pattern: var module = new function() {...} vs. var module = (function () {...}()); [duplicate] - javascript

I'm just trying to understand Javascript a little deeper.
I created a 'class' gameData that I only want ONE of, doesn't need a constructor, or instantiated.
So I created it like so...
var gameData = new function () {
//May need this later
this.init = function () {
};
this.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
}
Realizing that the 'new' keyword doesn't allow it to be instantiated and makes it available LIKE a static class would be in C#.
Am I thinking of this correctly? As static?

No, it is not static because it still has a constructor property pointing to your "anonymous" function. In your example, you could use
var gameData2 = new (gameData.constructor)();
to reinstantiate a second object, so the "class" (instance actually) is not really "static". You are basically leaking the constructor, and possibly the data that is bound to it. Also, a useless prototype object (gameData.constructor.prototype) does get created and is inserted in the prototype chain of gameData, which is not what you want.
Instead, you might use
a single, simple object literal (as in Daff's answer). That means you don't have a constructor, no closure-scoped private variables (you have used none anyway) and no (custom) prototype.
the (revealing) module pattern (as in jAndy's answer). There you'd have an IIFE to create closure-scoped variables, and can return any kind of object.
an actual constructor ("class") that can be instantiated later (when needed), and yields the same singleton object always.
This is what the singleton pattern would look like:
function GameData() {
if (this.constructor.singleton)
return this.constructor.singleton;
else
this.constructor.singleton = this;
// init:
// * private vars
// * public properties
// ...
}
GameData.prototype.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
var gameData = new GameData();
var gameData2 = new GameData();
gameData === gameData2 === GameData.singleton; // true
Yet, the prototype is quite useless because you have only one instance of GameData. It would only get interesting with inheritance.

There is no Class in ECMAscript, there is only Object.
When new is used to invoke a function, we call it a constructor function. This function somewhat auto returns a new object once it finished. Any data that is stored within that object using this (which references that newly created object) is returned as property of that object. Beside that, new sets a property called constructor to exactly this function.
In your case, you don't even really require the usage of new, you could easily re-write your code as follows:
var gameData = (function () {
var public = { },
private = { }; // any private data can get stored here
//May need this later
public.init = function () {
};
public.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
return public;
}());
This is called the factory pattern, singleton pattern, module pattern, and there might be some other names.

I think what you are looking for is just a simple JavaScript object:
var gameData = {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
}
}
If you want to use private variables create a revealing module pattern style wrapper. This is basically what jAndy suggested:
var gameData = (function() {
var private = 'private variable';
return {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
} else {
return false;
}
}
}
})();

Related

How to create objects properly in JS [duplicate]

I'm just trying to understand Javascript a little deeper.
I created a 'class' gameData that I only want ONE of, doesn't need a constructor, or instantiated.
So I created it like so...
var gameData = new function () {
//May need this later
this.init = function () {
};
this.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
}
Realizing that the 'new' keyword doesn't allow it to be instantiated and makes it available LIKE a static class would be in C#.
Am I thinking of this correctly? As static?
No, it is not static because it still has a constructor property pointing to your "anonymous" function. In your example, you could use
var gameData2 = new (gameData.constructor)();
to reinstantiate a second object, so the "class" (instance actually) is not really "static". You are basically leaking the constructor, and possibly the data that is bound to it. Also, a useless prototype object (gameData.constructor.prototype) does get created and is inserted in the prototype chain of gameData, which is not what you want.
Instead, you might use
a single, simple object literal (as in Daff's answer). That means you don't have a constructor, no closure-scoped private variables (you have used none anyway) and no (custom) prototype.
the (revealing) module pattern (as in jAndy's answer). There you'd have an IIFE to create closure-scoped variables, and can return any kind of object.
an actual constructor ("class") that can be instantiated later (when needed), and yields the same singleton object always.
This is what the singleton pattern would look like:
function GameData() {
if (this.constructor.singleton)
return this.constructor.singleton;
else
this.constructor.singleton = this;
// init:
// * private vars
// * public properties
// ...
}
GameData.prototype.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
var gameData = new GameData();
var gameData2 = new GameData();
gameData === gameData2 === GameData.singleton; // true
Yet, the prototype is quite useless because you have only one instance of GameData. It would only get interesting with inheritance.
There is no Class in ECMAscript, there is only Object.
When new is used to invoke a function, we call it a constructor function. This function somewhat auto returns a new object once it finished. Any data that is stored within that object using this (which references that newly created object) is returned as property of that object. Beside that, new sets a property called constructor to exactly this function.
In your case, you don't even really require the usage of new, you could easily re-write your code as follows:
var gameData = (function () {
var public = { },
private = { }; // any private data can get stored here
//May need this later
public.init = function () {
};
public.storageAvailable = function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
};
return public;
}());
This is called the factory pattern, singleton pattern, module pattern, and there might be some other names.
I think what you are looking for is just a simple JavaScript object:
var gameData = {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
}
else {
return false;
}
}
}
If you want to use private variables create a revealing module pattern style wrapper. This is basically what jAndy suggested:
var gameData = (function() {
var private = 'private variable';
return {
//May need this later
init : function () {
},
storageAvailable : function () {
if (typeof (Storage) !== "undefined") {
return true;
} else {
return false;
}
}
}
})();

JS: Javascript closure issue in prototype instance

As for a JS-newbie, I'm struggling with JS-closure. Googled enough, though can't understand why "this" is not available in "store" function. Any help will be appreciated:
;(function (win) {
var _af = function(storeObjectName, storeObjectValue) {
var self;
if (_af.prototype.instance) {
self = _af.prototype.instance;
} else {
self = Object.create(_af.prototype);
_af.prototype.instance = self;
self._init();
}
if (arguments.length == 1) return self.fire(storeObjectName);
if (arguments.length == 2) self.store(storeObjectName, storeObjectValue);
return self;
};
_af.prototype = {
afVariable: '_af',
afObject: {},
_init : function(){
this.afObject = this.get(self.afVariable);
},
store : (storeObjectName, storeObjectValue)=>{
// This throws the error, that this.get is not defined
this.get('_af');
},
get : storageObject=>{
if (!storageObject)
this.afObject = '_af';
else
this.afObject = '_someother'
}
}
win._af = _af;
}(window));
It's because you use a lambda expression ((...) => ...) instead of function() { ....
In JS this depends a lot on the context. In your case, since the prototype is an object, whenever you want to use this to refer to that object, you must do it in a function defined in the object like:
store : function(storeObjectName, storeObjectValue) {
// This throws the error, that this.get is not defined
this.get('_af');
},
or (also correct):
store(storeObjectName, storeObjectValue) {
// This throws the error, that this.get is not defined
this.get('_af');
},
Note you are doing it correctly for _init, but not for store and get
When you use the lambda syntax, this will refer to the current this, when a function is created, so it will be window.
Also avoid using get as a function / or any other name because it is used for defining getters.

jQuery logger plugin

I'm working on a jQuery plugin that allows you to log any javascript class or object.
The idea is to override each function inside the object, or prototype of a function.
(function($)
{
"use strict";
$.log = function(object, logger)
{
if (!$.isFunction(logger))
{
logger = function(name, args)
{
console.log(name + "(" + $.makeArray(args).join(", ") + ")");
};
}
var s = $.isFunction(object) ? object.prototype : object;
for (name in s)
{
var fn = s[name];
if ($.isFunction(fn))
{
s[name] = (function(name, fn)
{
return function()
{
logger(name, arguments);
return fn.apply(this, arguments);
};
})(name, fn);
}
}
};
})(jQuery);
This seems to work for logging individual plugins. For example $.log($.ui.tabs); logs all the function calls inside the tabs prototype.
But when I want to log all of jQuery $.log($); it's giving me some reference error.
I can't figure out why I'm getting this error. I'm under the impression it has something to do with either this or the arguments being passed, but I'm not sure.
Edit: Now I think about It some more it might also be caused because the overridden function always returns.
I created a fiddle to demo the problem: http://jsfiddle.net/Sj6xN/4/
EDIT:
This is the code i ended up with, so far working perfectly:
(function($)
{
"use strict";
var Logger = function(options)
{
this.options = $.extend(this.defaults, options);
};
Logger.prototype = {
defaults:
{
inherited: false,
deep: false,
logWriter: function(name, args)
{
console.log("CALL: " + name + "(" + $.makeArray(args).join(", ") + ")");
}
},
augment: function(object)
{
var self = this;
// Make sure this object is not already augmented
if (object.__isAugmented__)
{
return;
}
// Set 'isAugmented' to prevent recursion
object.__isAugmented__ = true;
// Loop through the object
for (var name in object)
{
var originalFunction = object[name];
// If it's a function and the function is not inherited or 'inherited' is enabled augment it
if ($.isFunction(originalFunction) && (object.hasOwnProperty(name) || self.options.inherited))
{
// Wrap in self executing function so references to 'name' and 'orginalFunction' are maintained
object[name] = (function(name, originalFunction)
{
// If the function has a prototype and 'deep' is enabled augment that as well
if (self.options.deep && originalFunction.prototype)
{
self.augment(originalFunction.prototype);
}
var augmentedFunction = function()
{
// Execute log writer
self.options.logWriter(name, arguments);
// Call original function
return originalFunction.apply(this, arguments);
};
// Inherit prototype of original function
augmentedFunction.prototype = originalFunction.prototype;
// Return the augmented function
return augmentedFunction;
})(name, originalFunction);
}
// If it's a plain object and 'deep' is enabled augment that as well
else if (self.options.deep && $.isPlainObject(originalFunction))
{
self.augment(originalFunction);
}
}
}
};
$.log = function(object, options)
{
var logger = new Logger(options);
// If the object is a function use it's prototype, otherwise assume a plain object
object = $.isFunction(object) ? object.prototype : object;
// Augment
logger.augment(object);
};
})(jQuery);
Can be used like this:
$.log(<object or function> [,
{
inherited: <bool>,
deep: <bool>,
logWriter: <function(name, args)>
}]);
Well look closely to the error.
Uncaught ReferenceError: name is not defined
Means you haven't defined name and since you are in strict mode, you can't use a variable without defining it(normally if you do it, it'll be a global variable, but not in strict mode). So if you write a var name before it you won't get this error anymore.
Though there is another error for not having tab method. The other error says tabs is not a method of the object which is because when you wrap the function, you didn't inherit the prototype, so when the function is called with new, it doesn't have prototype functions(tabs is one of them).
Here's the fixed code : http://jsfiddle.net/Sj6xN/8/

Javascript library development scopes and namespaces

we currently learn some Javascript stuff in a course at the university.
For that we implement a library for common tasks like show(), hide(), write and such things.
Currently im running with an implementation like:
var myLib_maker = function () {
/*
private scope
*/
var debuggingMode=true;
var currentElement=null;
/*
end private scope
*/
return {
getElement: function (id) {
var o;
if (typeof id === 'string') { o = document.getElementById(id); }
if (!!(o && o.nodeType !== 1)) {
throw {
name: 'Type Error',
message: 'Wrong node type at id: '+id
}
}
currentElement=o;
return this;
},
getCurrentElement: function() {
console.log(currentElement)
return currentElement;
},
isVisible: function () {
return this.getCurrentElement().style.display.toLowerCase() === "block";
},
show: function () {
this.debug("show "+this.getCurrentElement())
this.getCurrentElement().style.display = "block";
return this;
},
hide: function () {
this.debug("hide "+this.getCurrentElement())
this.getCurrentElement().style.display = "none";
return this;
},
toggle: function() {
this.debug("toggle "+this.getCurrentElement())
this.isVisible() ? this.hide(): this.show();
return this;
},
write: function (content){
this.debug("write to"+this.getCurrentElement().id);
var tg = this.getCurrentElement().tagName.toLowerCase();
if (tg === 'input' || tg === 'textarea') {
currentElement.value = content;
} else {
currentElement.innerHTML = content;
}
return this
},
debug: function (what) {
if (debuggingMode===true){
console.log("[DEBUG] "+what);
}
return this;
}
};
}
var myLib=myLib_maker();
Than I have an external function (for testing) to switch 2 textareas contents.
function switchEditors(id1, id2){
c1=myLib.getElement(id1).getCurrentElement().value;
c2=myLib.getElement(id2).getCurrentElement().value;
myLib.getElement(id1).write(c2)
myLib.getElement(id2).write(c1)
}
I first tried with the following code, which obviously does not work, cause I overwrite my private currentElement and so I write always to id2
function switchEditors(id1, id2){
tmp=myLib.getElement(id1).getCurrentElement().value
myLib.getElement(id1).write(myLib.getElement(id2).getCurrentElement().value)
myLib.getElement(id2).write(tmp)
}
But what I really wanted initially was not using a private currentElement variable.
The first implementation of the write method extended the Element Object
Element.prototype.write= function (content){
var tg = this.tagName.toLowerCase();
if (tg === 'input' || tg === 'textarea') {
this.value = content;
} else {
this.innerHTML = content;
}
return this;
}
and such the getElement function returned
document.getElementById(id)
I want cascading (I hope this is the right word -> I mean the myLib.getElement("myid").show().hide() concatenation thing) and getting direct access to
all Element attributes but we must not use global scope for our library, so I have to encapsulate my library in any way.
So is there an elegant way to use the cascading thing and be able to get a direct access to all attributes on an element object without implementing each method within the global element scope?
Or is my lib desing completely wrong and has to be done totally different.
If so, just tell me, I appreciate any help.
(I tried to figure out how jQuery actually implement these things, but didn't get a real clue how it is done ... too much code ... :) )
I hope I described my wishes and requirements. If not please ask for more specific details.
As you've figured out, the currentElement is shared between calls to getElement. Instead you could create a new instance of myLib-object with Object.create and bind currentElement to that.
getElement: function (id) {
var o, self = Object.create(this);
/* ... */
self.currentElement = o;
return self;
}
And use this.currentElement throughout so that each call uses its own current element.
While Magnar's solution will work with this (singleton) pattern, it is a better idea to avoid creating a whole new object each time you call getElement. There is a reason for creating "classes" instead of singletons.
You can do it like this:
var MyLib_Maker = (function () { // I capitalized the class as a helpful
// convention recommended by Douglas Crockford
// Private static vars
var debuggingMode = true;
var currentElement = null;
// Private static methods
function _myMethod (x, y) { // call below by _myMethod(3,4);
return x * y;
}
// Private instance methods (but only if called properly:
// invoke below by _instMethod.call(this, 3, 4); )
function _instMethod (x, y) {
return this.anInstanceNumber * x * y;
}
// Private instance properties (quite cumbersome but doable if you
// absolutely must--e.g., for classes whose objects need to be clean when iterated)
// See http://brettz9.blogspot.com/2009/02/true-private-instance-variables-in.html
// and http://brettz9.blogspot.com/2009/02/further-relator-enhancements.html
// (put the Relator inside the closure if you don't want it reusable (and public),
// but then your extending classes must be inside the closure too)
function MyLib_Maker (arg1, arg2) {
// I recommend the following check to allow your class to be
// instantiated without the 'new' keyword (as in jQuery/$):
if (!(this instanceof MyLib_Maker)) {
return new MyLib_Maker(arg1, arg2);
}
// Other constructor code here
// ...
}
// Methods added on the prototype benefit from merely
// providing a low-memory reference across all instances;
// this will avoid adding a whole new object unnecessarily
// into memory
MyLib_Maker.prototype.getElement = function () {
// ....
return this; // Keep the chain going (if not public
// properties, you could add a method which also avoids
// extending the chain, like $(el).get() in jQuery
};
return MyLib_Maker;
}()); // We can invoke immediately to wrap up the closure
// Usage example:
var mlm = MyLib_Maker(2, 3).getElement().doSomething();
By the way, what you describe is called chaining; cascading is used in the likes of CSS to indicate that like different waves out of a waterfall, one may write over the other, as you can do by writing rules which override prior ones in CSS.
And it is good you moved away from overriding the Element object because, whatever the browser incompatibilities, this is the worst kind of global namespace pollution because it affects all elements, increasing the chance that another library which depends on that method (or which is careless in overriding the built-in prototypes itself) may get you unexpected results.

Method delegation in Javascript/jQuery?

I have this code:
var myWidget = $('#myWidget');
and calls like this elsewhere:
myWidget.hide();
myWidget.slideToggle();
These work of course because jQuery adds these methods.
Now, let's say I'm doing some refactoring to make myWidget a proper object with its own custom methods and state:
var myWidget = (function() {
// private stuff
var actualJQueryObject = $('#myWidget');
return {
publicMethod: function() {...},
// MAGIC!
}
})()
but I want to have all the calls that expect a jQuery object, which are all around my code, to still work even though myWidget is no longer a jQuery object, because myWidget knows how to delegate these calls to actualJQueryObject.
Is this possible?
You could also extend your jQuery object, with another object that has your custom methods:
var myWidget = function() {
// private stuff
var actualJQueryObject = $('#myWidget');
var extensionMethods = {
publicMethod: function() { alert('public method!'); }
}
return $.extend(actualJQueryObject, extensionMethods);
}();
Just be careful with the name of your extension methods, to not clash with any other jQuery defined function.
You can try the above snippet here.
One option is using the original jquery object as a prototype.
function wrap(jqObject) {
function MyNewType() {
this.changeFontSize = function(a) {
this.css({fontSize : this.size});
};
}
MyNewType.prototype = jqObject;
return new MyNewType;
}
var obj = wrap($('#someitem'));
obj.size = 50; // obj.size
obj.changeFontSize(); // obj.changeFontSize
obj.hide(); // $.hide
obj.fadeIn("slow"); // $.fadeIn
I've written a plugin that might help you. It's basically a plugin for writing plugins. This dev group post explains it and has some code samples:
http://groups.google.com/group/jquery-dev/browse_thread/thread/664cb89b43ccb92c/72cf730045d4333a?hl=en&q=structure+plugin+authoring#72cf730045d4333a
And the source is here:
http://code.google.com/p/jquery-plugin-dev/source/browse/trunk/jquery.plugin.js
EDIT:
I created a function that has similar functionality to that plugin:
jQuerify = function(fn) {
function plugin() {
var instantiate = false;
// check to see if it has any prototyped methods (we only need one iteration to do this)
for (var i in construct.prototype) {
instantiate = true;
break;
}
// if there are prototyped methods, return an instance (since an instance's return value won't vary)
// otherwise just call it using apply so the return value can vary
return instantiate
? new construct(this, arguments)
: construct(this, arguments);
}
function construct(parent, args) {
// 'this' will not mimic jQuery unless given the length property
this.length = 0;
this.selector = parent.selector;
this.context = parent.context;
// mimic 'this' in jQuery, but for the plugin namespace
Array.prototype.push.apply(this, $.makeArray(parent));
// return the constructors return value
// should be 'this' if you want to chain the new namespace
return fn.apply(this, arguments);
}
// copy all static properties and methods
for (var i in fn) {
plugin[i] = fn[i];
}
// allow .fn and copy all instance properties and methods; the last part is for IE
plugin.fn = construct.prototype = plugin.prototype = fn.prototype;
return plugin;
}
This allows you to add custom objects to jQuery as a plugin while using 'this' to refer to the selected objects and also allows you to have an unlimited depth to your namespace:
function test1() {
return this;
}
test1.prototype.getHtml1 = function() {
return $(this).html();
}
function test2() {
return this;
}
test2.prototype.getHtml2 = function() {
return $(this).html();
}
function test3() {
return this;
}
test3.prototype.getHtml3 = function() {
return $(this).html();
}
jQuery.fn.test1 = jQuerify(test1);
jQuery.fn.test1.fn.test2 = jQuerify(test2);
jQuery.fn.test1.fn.test2.fn.test3 = jQuerify(test3);
jQuery(function($) {
alert($('body').test1().getHtml1());
alert($('body').test1().test2().getHtml2());
alert($('body').test1().test2().test3().getHtml3());
});

Categories