I created a javascript class as follow:
var MyClass = (function() {
function myprivate(param) {
console.log(param);
}
return {
MyPublic : function(param) {
myprivate(param);
}
};
})();
MyClass.MyPublic("hello");
The code above is working, but my question is, how if I want to introduce namespace to that class.
Basically I want to be able to call the class like this:
Namespace.MyClass.MyPublic("Hello World");
If I added Namespace.MyClass, it'll throw error "Syntax Error".
I did try to add "window.Namespace = {}" and it doesn't work either.
Thanks.. :)
Usually I'd recommend doing this (assuming Namespace is not defined elsewhere):
var Namespace = {};
Namespace.MyClass = (function () {
// ...
}());
A more flexible, but more complex, approach:
var Namespace = (function (Namespace) {
Namespace.MyClass = function() {
var privateMember = "private";
function myPrivateMethod(param) {
alert(param || privateMember);
};
MyClass.MyPublicMember = "public";
MyClass.MyPublicMethod = function (param) {
myPrivateMethod(param);
};
}
return Namespace
}(Namespace || {}));
This builds Namespace.MyClass as above, but doesn't rely on Namespace already existing. It will declare and create it if it does not already exist. This also lets you load multiple members of Namespace in parallel in different files, loading order will not matter.
For more: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
YUI has a nice method for declaring namespaces
if (!YAHOO) {
var YAHOO = {};
}
YAHOO.namespace = function () {
var a = arguments,
o = null,
i, j, d;
for (i = 0; i < a.length; i = i + 1) {
d = ("" + a[i]).split(".");
o = YAHOO;
for (j = (d[0] == "YAHOO") ? 1 : 0; j < d.length; j = j + 1) {
o[d[j]] = o[d[j]] || {};
o = o[d[j]];
}
}
return o;
}
Place it above any function that you want to namespace like this:
YAHOO.namespace("MyNamespace.UI.Controls")
MyNamespace.UI.Controls.MyClass = function(){};
MyNamespace.UI.Controls.MyClass.prototype.someFunction = function(){};
This method is actually stand-alone and can easily be adapted to your application. Just find and replace "YAHOO" with your application's base namespace and you'll have something like MyOrg.namespace. The nice thing with this method is that you can declare namespaces at any depth without having to create object arrays in between, like for "UI" or "Controls"
A succinct way to do what you're asking is create "Namespace" as an object literal like this:
var Namespace = {
MyClass : (function() {
... rest of your module
})();
};
This could cause conflicts if you wanted to attach other details to Namespace in other files, but you could get around that by always creating Namespace first, then setting members explicitly.
Checkout the namespace library, it is very lightweight and easy to implement.
(function(){
namespace("MyClass", MyPublic);
function MyPublic(x){
return x+1;
}
})();
It supports automatically nesting as well
namespace("MyClass.SubClass.LowerClass", ....)
Would generate the necessary object hierarchy, if MyClass, SubClass did not already exist.
bob.js has nice syntax to define JavaScript namespace:
bob.ns.setNs('myApp.myMethods', {
method1: function() {
console.log('This is method 1');
},
method2: function() {
console.log('This is method 2');
}
});
//call method1.
myApp.myMethods.method1();
//call method2.
myApp.myMethods.method2();
(function($){
var Namespace =
{
Register : function(_Name)
{
var chk = false;
var cob = "";
var spc = _Name.split(".");
for(var i = 0; i<spc.length; i++)
{
if(cob!=""){cob+=".";}
cob+=spc[i];
chk = this.Exists(cob);
if(!chk){this.Create(cob);}
}
if(chk){ throw "Namespace: " + _Name + " is already defined."; }
},
Create : function(_Src)
{
eval("window." + _Src + " = new Object();");
},
Exists : function(_Src)
{
eval("var NE = false; try{if(" + _Src + "){NE = true;}else{NE = false;}}catch(err){NE=false;}");
return NE;
}
}
Namespace.Register("Campus.UI.Popup")
Campus.UI.Popup=function(){
defaults={
action:'',
ispartialaction:'',
customcallback:'',
confirmaction:'',
controltoupdateid:'',
width:500,
title:'',
onsubmit:function(id){
var popupid=id+"_popupholder";
if(this.ispartialaction){
$.ajax({
url:this.action,
type:"Get",
context:this,
success:function(data){
$('#'+id).parents('body').find('form').append("<div id'"+popupid+"'></div>");
var ajaxContext=this;
$("#"+popupid).dialog({
autoopen:false,
model:true,
width:this.width,
title:this.title,
buttons:{
"Confirm":function(){
if(ajaxContext.customcallback==''){
var popupform=$(this).find("form");
if(popupform.isValid()){
$.post(ajaxContext.confirmaction,popupform.serialize(),function(d){
if(d!='')
{
$.each(d.Data,function(i,j){
switch(j.Operation)
{
case 1:
if($('#'+j.ControlClientID).is("select"))
{
$('#'+j.ControlClientID).val(j.Value);
$('#'+j.ControlClientID).change();
}
else if($('input[name="'+j.ControlClientID+'"]').length>0)
{
$('input[name="'+j.ControlClientID+'"][value="'+j.Value+'"]').prop("checked",true);
}
break;
case 2:
if($('#'+j.ControlClientID).is("select"))
{
$('#'+j.ControlClientID).append("<option selected='selected' value=\""+j.Value+"\">"+j.Text+"</option>");
}
else
{
var len=$('input[name="'+j.ControlClientID+'"]').length;
$('#'+j.ControlClientID+"list").append('<li><input type="checkbox" name="'+j.ControlClientID+'" value="'+j.Value+'" id="ae'+j.ControlClientID+len+'"/><label for "ae'+j.ControlClientID+len+'">'+j.Text+'</label>');
}
break;
case 0:
$('#'+j.ControlClientID).val(j.Value);
breakl
default:break;
}
});
popupform.parent().dialog("destroy").remove();
$("#"+ajaxContext.controltoupdateid).change();
}
});
}
}
else
{
executeByFunctionName(ajaxContext.customcallback,window,new Array());
}
},
"Cancel":function(){
$(this).dialog("close");
}
}
});
$("#"+popupid).dialog("open");
$("#"+popupid).empty().append(data);
},
error:function(e)
{
alert(e);
}
});
}
else
{
var frm=document.createElement("form");
frm.id="CampusForm";
frm.name="CampusForm";
frm.action=this.action;
frm.method="post";
var arr=$($("#"+id).closest("body").find("form")).serializeArray();
$.each(arr,function(i,j){
var hidd=document.createElement("input");
hidd.type="hidden";
hidd.name=j.name;
hidd.value=j.value;
frm.appendChild(hidd);});
document.appendChild(frm);
frm.submit();
}
}
},
clicksubmit=function(){
var opts=$(this).data("CampusPopup");
opts.onsubmit($(this).attr("id"));
return false;
};
return
{
init:function(opt){
var opts=$.extend({},defaults,opt||{});
$(this).data('CampusPopup',opts);
$(this).bind("click",clicksubmit);
}};
}();
$.extend({CampusPopup:Campus.UI.Popup.init});
})(jQuery)
Automating namespaces declaration in javascript is very simple as you can see:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util);
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
This is the design pattern I use which allows for nested namespaces as well as adding to the namespace later (even from a separate JS file) so you don't pollute the global namespace:
Example: JsFiddle
(function ($, MyObject, undefined) {
MyObject.publicFunction = function () {
console.log("public");
};
var privateFunction = function () {
console.log("private");
};
var privateNumber = 0;
MyObject.getNumber = function () {
this.publicFunction();
privateFunction();
privateNumber++;
console.log(privateNumber);
};
// Nested namespace
MyObject.nested = MyObject.nested || {};
MyObject.nested.test = function (text) {
console.log(text);
};
}(jQuery, window.MyObject = window.MyObject || {}));
// Try it
MyObject.getNumber();
MyObject.nested.test('Nested');
Here is how to add to MyObject from another JavaScript file:
(function ($, MyObject, undefined) {
MyObject.newFunction = function () {
console.log("Added");
};
}(jQuery, window.MyObject = window.MyObject || {}));
// Pass `jQuery` to prevent conflicts and `MyObject` so it can be added to, instead of overwritten
This resource helped me learn all about the different JS design patterns: http://addyosmani.com/resources/essentialjsdesignpatterns/book/
To create new JavaScript namespaces (like Math), I personally define the following base class that can be extended, but not instantiated:
class Namespace {
constructor() { throw TypeError("cannot instantiate a namespace") }
}
Subclasses will inherit constructor or override it with a method that calls super, so instantiation results in a TypeError either way.
The actual namespaces are defined by extending Namespace with any number of static properties (which can reference one another):
class ASCII extends Namespace {
static whitespace = "\t\n\r\v ";
static digits = "0123456789";
static uppers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static lowers = ASCII.uppers.toLowerCase();
static alphas = ASCII.uppers + ASCII.lowers;
static alphanumerics = ASCII.alphas + ASCII.digits;
}
const isDigital = candidate => ASCII.digits.includes(candidate);
The example use a bunch of string constants, but a namespace can contain any types of value, including functions (defined as static methods).
Related
I typically see examples of the revealing prototype pattern as shown in syntax #2 below, but i find syntax #1 more consistent. Is there anything different about them other than syntax? Functionally, performance wise, or other?
syntax #1:
function MyClass1(name){
this.name = name;
}
MyClass1.prototype = new function () {
var static = 0;
var getStatic = function () {
return static;
}
this.incStatic = function () {
static++;
return getStatic.call(this);
}
this.constructor = MyClass1
};
exactly the same as this #2:
function MyClass2(name){
this.name = name;
}
MyClass2.prototype = function () {
var static = 0;
function getStatic () {
return static;
}
function incStatic() {
static++;
return getStatic.call(this);
}
return {
incStatic:incStatic,
constructor:MyClass2
};
}();
Here is a fiddle demonstrating the exact same behaviors: http://jsfiddle.net/arctelix/FSk8z/
It appears that both syntax have exactly the same outcome. However, I have never seen an example as shown in #1, so i have to wonder why? For me # 1 is just a more constant syntax and i hate having to identify public members in a special return block.
Personally I consider it improper to reassign something.prototype. Instead, extend the prototype:
(function() {
var static = 0;
MyClass.prototype.getStatic() {return static;}
MyClass.prototype.incStatic() {return static++;}
})();
This whole thing came about because i am creating an MVC framework that utilizes a generic Class constructor. I ran these variations in the larger context of the Class constructor with two different implementation methods. Method 1 reassigns the prototype where method 2 extends it. Method 1 has a uniform prototype chain where method 2 adds a function prototype on top of the object prototype for syntax #1. The performance is about equal for both method 1 and 2.
Blue & Red = syntax #1.
Teal & Green = syntax #2.
Yellow & purple = a variation on syntax #2.
var Class = function (methods, options) {
//allow for Proper class name to show up in browser devtools
options = options || {}
var debug = options.debug || false
var protoTest = options.protoTest || 0
var pInternal = options.pInternal || true
var klassName = methods.constructor.name
console.log('------protoTest =', protoTest, '/ debugClass =', debug, '/ pInternal =', pInternal, '/ klassName = ',klassName)
//compile the constructor & internalMembers
var Class = function () {
//console.log('Class() is building:', !(init instanceof init))
//provide inernal object for constructor
if (pInternal) this.internal = {}
this.constructor.apply(this, arguments);
//remove internal from public scope
if (pInternal){
var int = this.internal
delete this.internal
}
//populate self with this and internal vars
if (pInternal){
var self = {pub:this, int:{}};
for (var v in int){
self.int[v] = int[v];
}
}else var self = this
// Instantiate internalMembers with self
var include = methods.include;
if (include) include.call(this, self);
};
//create constructor function with className (fixes class name in debugger)
if (debug == true && klassName) {
var klass = new Function("init", "return function " + klassName + "(){ init.apply(this,arguments) };")(Class);
}else var klass = Class
console.log('---type', typeof methods.prototype)
if (typeof methods.prototype == 'object'){
//must use traditional revealing prototype
var prototype = methods.prototype;
if (protoTest==0){
//overides prototype
if (prototype) klass.prototype = prototype;
}else{
//does not overide prototype
for (var p in prototype) klass.prototype[p] = prototype[p]
}
}
//create prototype from Class method
//----------------test 0
else if (protoTest==0){
//overides prototype (new has extra proto in chain)
var prototype = methods.prototype;
if (prototype) klass.prototype = new prototype();
}
//----------------test 1
else if (protoTest == 1){
//does not overide prototype and has uniform chain
var pms = new methods.prototype()
for (var p in pms) klass.prototype[p] = pms[p]
}
//----------------end test
//add other Class methods to prototype
var exclude = ['include', 'initialize', 'prototype'];
for (var property in methods) {
if (exclude.indexOf(property) == -1) {
klass.prototype[property] = methods[property];
}
}
return klass; //return the class
};
All the tests: http://jsperf.com/revealing-proto-test/4
The fiddle: http://jsfiddle.net/arctelix/Cp4nG/
There is a debug mode with tests as well: http://jsperf.com/revealing-proto-test/3
I want to write a small game using JavaScript and <canvas> but first I want to nail the "correct" or at least common approach to working with Objects.
One topic I am having trouble understanding in particular is how I could implement overriding of method.
When I create an Object, I may have this:
function MyObject()
{
var base = {};
base.i = 0;
base.update = function()
{
base.i ++;
}
return base;
}
Then when I create another Object that should start with the same members, I use this:
function AnotherObject()
{
var base = new MyObject();
base.j = 0;
return base;
}
I want to add more content to AnotherObject.update() while still running the logic I have in MyObject.update(), but when I do this within AnotherObject():
base.update = function()
{
j ++;
}
Then I of course lose the logic I added in MyObject.update().
How can I write AnotherObject.update() so that it also calls the original update() method defined by MyObject?
First, I'd suggest you read this excellent excellent MDN article. It will enlighten you.
You can achieve subclassing this way:
function MyObject() {
this.i = 0;
}
MyObject.prototype.update = function() {
this.i++;
}
function AnotherObject() {
MyObject.call(this);
this.j = 0;
}
AnotherObject.prototype = new MyObject;
AnotherObject.prototype.constructor = AnotherObject;
AnotherObject.prototype.update = function() {
MyObject.prototype.update.call(this);
this.j++;
}
obj = new AnotherObject();
console.log(obj.i); //0
console.log(obj.j); //0
obj.update();
console.log(obj.i); //1
console.log(obj.j); //1
console.log(obj instanceof MyObject) //true
console.log(obj instanceof AnotherObject) //true
+1 for zzzzBov's comment. You're using base when you should be using prototype. Not within the constructor function, but rather after the constructor function to further refine the class definition.
function MyObject() {
this.value = 5;
}
MyObject.prototype.update = function() {
this.value++;
}
Var newObject = new MyObject();
newObject.update =function() {
value--;
}
As others have suggested you should follow prototype based inheritance. That is the right way to do it.
But as a solution to what you have done so far you can do as shown below
function MyObject() {
var base = {};
base.i = 0;
base.update = function () {
this.i++;
}
base.show = function () {
console.log("i is " + this.i);
}
return base;
}
function AnotherObject() {
var base = new MyObject();
base.j = 0;
var update = base.update; // proxy variable that refers to original `update`
base.update = function () {
update.call(this); // invoke original `update`
this.j++;
}
var show = base.show; // proxy variable that refers to original `show`
base.show = function () {
show.call(this); // invoke original `show`
console.log("j is " + this.j);
}
return base;
}
var t = AnotherObject();
t.update();
t.show();
Based on an answer I received in my previous question I would like to know how to simplify the following JavaScript pattern.
By simplifying I mean keeping it DRY by not repeating Module.*method.
ex.
Module.one = function() {
//one
};
Module.two = function() {
//two
};
This is how I believe it should look like:
Moduje.js
var Module = (function(Module) {
init = function() {
console.log("init");
};
return Module;
})(Module || {});
Module.Users.js
var Module = Module || {};
Module.Users = (function(Users) {
init = function() {
console.log("Module.Users.init");
};
return Module.Users;
})(Module.Users || {});
Here is the original code.
Moduje.js
var Module = (function(Module) {
Module.init = function() {
console.log("init");
};
return Module;
})(Module || {});
Module.Users.js
var Module = Module || {};
Module.Users = (function(Users) {
Users.init = function() {
console.log("Module.Users.init");
};
return Users;
})(Module.Users || {});
Well:
var Module = (function(Module) {
init = function() {
console.log("init");
};
return Module;
})(Module || {});
No, that won't work. You're creating the default value for "Module" outside that function. You've forgotten var in the declaration of "init" too, which in this case sort-of makes it work, but in a broken way (because it's a global variable, if not an error due to "strict" mode possibly being enforced). Since you're declaring "Module" with that statement, passing "Module" in as a (possible) argument doesn't make any sense.
I don't know what the word "simplify" means to you; the original looks OK to me.
edit — if what you'd like to do is get rid of repeated references to the base object, you can use an "extend" function, either from a library or that you write yourself:
function extend(target) {
var sources = Array.prototype.slice.call(arguments, 1), source;
for (var i = 0; i < sources.length; ++i) {
source = sources[i];
for (var key in source) {
if (source.hasOwnProperty(key))
target[key] = source[key];
}
}
return target;
}
Then you can do something like this:
var Module = createModule(); // make an object however you want
Module = extend(Module, {
newProperty_1: "hello world",
newProperty_2: function() {
// this will become a method on "Module"
},
newProperty_3: {
subObjectProperty: "whatever"
}
});
Am I doing something wrong or is this just not possible:
(function(namespace,undefined)
{
//Private properties and methods
var foo="bar";
function test(){return foo;}
//Public properties and methods
namespace.foobar=foo+"123";
namespace.showFoo=function(){return test();};
})(window.namespace=window.namespace || {});
Then I try to "extend" the above namespace and add a new method:
(function(namespace,undefined)
{
//Public method
namespace.sayGoodbye=function()
{
alert(namespace.foo);
alert(namespace.bar);
alert(test());
}
})(window.namespace=window.namespace || {});
The alert shows undefined for the properties and throws an error for the test() method.
Thanks.
Why would you expect to have foo and bar available ? Those identifiers are never assigned to your namespace object anywhere.
Any variable that is declared with var is only available in the Function(-Context) of the current Activation/Variable Object. Same goes for function declarations, in your case, test(). Both these are only stored within the AO from the first anonymous function and are not stored within your namespace object. You would have to explicitly assign the values
namespace.foo = foo;
namespace.bar = "hello I am bar";
You have several bugs in your code. That code is working. Example.
(function(namespace)
{
if(namespace === undefined) {
window.namespace = namespace = {};
}
//Private properties and methods
var foo="bar";
function test(){return foo;}
//Public properties and methods
namespace.foobar=foo+"123";
namespace.showFoo=function(){return test();};
})(window.namespace);
(function(namespace)
{
if(namespace === undefined) {
window.namespace = namespace = {};
}
//Public method
namespace.sayGoodbye=function()
{
alert(namespace.foobar);
alert(namespace.showFoo());
}
})(window.namespace);
window.namespace.sayGoodbye();
Bugs:
1. You never set the variable window.namespace.
2. If you declare variables/functions in a private way in a function then only this specific function can access these variables/functions.
If you want to use a namespace you can do it like this:
var namespace = (function(){
var private = "private";
function privateFunc() {
return private;
}
return {
"publicFunc": function(){return privateFunc()}
}
})();
namespace.publicFunc() === "private";
//alert(namespace.publicFunc());
// extend namespace
(function(namespace){
var private = "other private";
namespace.newFunc = function(){return private};
})(namespace);
namespace.newFunc() === "other private";
//alert(namespace.newFunc());
Namespaces declaration and extending of namespaces:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util); //or namespace('ivar.util.string');
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
What is the proper way to declare a namespace? I've just read "Developing Large Web Applications" and the author suggests using:
if (!window.YourNamespace) {
YourNamespace = {};
}
seems easy enough.. but I see all the javascript libraries for declaring namespaces and alternate methods. Isn't there a standard way to do this? Any problems with the above?
I've seen this convention used several places.
window.YourNamespace = window.YourNamespace || {};
The mentioned namespace-declarating-way by book author is indeed quite good one. But when you need to repeat it in several files and the namespace has several subnamespaces, it can get quite tedious:
if (!window.Foo) {
Foo = {};
}
if (!window.Foo.Bar) {
Foo.Bar = {};
}
if (!window.Foo.Bar.Baz) {
Foo.Bar.Baz = {};
}
etc...
Instead you should write a simple function that takes care of declaring the namespaces for you:
function namespace(ns) {
var parts = ns.split(/\./);
var obj = window;
for (var i=0; i<parts.length; i++) {
var p = parts[i];
if (!obj[p]) {
obj[p] = {};
}
obj = obj[p];
}
}
Now you can declare the whole nested namespace with just one line:
namespace("Foo.Bar.Baz");
In ExtJS framework this is basically what Ext.ns() function does. I don't really know about other libraries.
var Utils = {
namespace : function(name) {
return window[name] = window[name] || {};
}
};
or if you prefer your way use:
if (typeof window.YourNamespace === 'undefined') {
YourNamespace = {};
}
There is no standard way as you'll see between frameworks but they do go beyond the basics so that for example X.Y.Z, it will create all objects in that chain if they don't already exist.
bob.js handles namespaces like this:
bob.ns.setNs('YourNamespace', {
/*define your members here. e.g.:*/
method1: function () { /*...*/ }
});
// now, merge another, sub-namespace.
bob.ns.setNs('YourNamespace.YourSubNamespace', {
method2 function () { /*...*/ }
});
//call methods:
YourNamespace.method1();
YourNamespace.YourSubNamespace.method2();
Automating namespaces declaration in javascript is very simple as you can see:
var namespace = function(str, root) {
var chunks = str.split('.');
if(!root)
root = window;
var current = root;
for(var i = 0; i < chunks.length; i++) {
if (!current.hasOwnProperty(chunks[i]))
current[chunks[i]] = {};
current = current[chunks[i]];
}
return current;
};
// ----- USAGE ------
namespace('ivar.util.array');
ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);
namespace('string', ivar.util);
ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo);
Try it out: http://jsfiddle.net/stamat/Kb5xY/
Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/
Some example of namespace function:
namespace = function(ns){
arr = ns.split(".")
parent = window
var temp
while( ( temp = arr.shift()) !== undefined){
parent[temp] = parent[temp] || {}
parent = parent[temp]
}
}
You can then use it as:
namespace("your.own.namespace")
your.own.namespace.Car= function () {
this.speed = 30;
}