Namespacing in terms of static declarations and the call - javascript

I have the following code: http://jsfiddle.net/pepNU/1/
I want to make a static reference to "YourGame" and indeed the "Settings" inside it, so the only way I could think of doing this was add it as a private variable(class if you will) and then reference it as a variable in the return of YourGame, thus it could be called like:
YourGame.Settings.GetFrameRate();
What are your thoughts on this? Should I be doing something more like this to namespace:
YourGame.Settings = function...
I obviously cannot just plonk the function inside the return as I then cannot get to the GetFrameRate() function returning within the Settings with a simple call like the aforementioned

What you did is fine, but since you just need a single instance and there is no constructor logic, you could also have used an object literal:
var YourGame = {
Settings : {
// ...
},
// ...
}
If you need an instantiable "class" with "static" properties, you can also add properties to the constructor directly:
var YourGame = function() {
// constructor logic
}
YourGame.foo = 10; // static property
var game = new YourGame; // instance
game.foo; // undefined
YourGame.foo; // 10

Related

Using this or new in JS?

I've got 3 codes :
var control = new Control();
function Control() {
this.doSomethingElse = function() {...}
this.doSomething = function () {
control.doSomethingElse();
}
}
Or
var control = new Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
}
Or
var control = Control();
function Control() {
var self = this;
this.doSomethingElse = function() {...}
this.doSomething = function () {
self.doSomethingElse();
}
return self;
}
Important : The function is a controller, and just declared once. Then I'm using "control" everywhere in my code...
I was wondering if the control.doSomethingElse() was slow ?
In the end, what is the right thing to do and/or the fastest code in those exemple ?
Thanks !
The first is wrong - an object should never internally use the variable name by which it is known outside. Other code could change that variable to point to something else, breaking this code.
The third is also wrong - when calling Control() without new the assignments to this.foo inside will end up getting attached to the global object (except in strict mode, where there's no implicit this on bare function calls, so the assignment to this.doSomethingElse tries to attach to undefined, causing a runtime error).
That only leaves the second as appropriate, but ultimately it's a question of correctness, not performance.
Do not define methods in constructor - that means defining them every time an instance is created. Use Control.prototype.foo = function() {} instead. Also you do not need to return this if you're using new operator - that's the whole point of new operator.
The recommended approach is this:
function MyClass(param1) {
// Here we're changing the specific instance of an object
this.property1 = param1;
}
// Prototype will be shared with all instances of the object
// any modifications to prototype WILL be shared by all instances
MyClass.prototype.printProperty1 = function() {
console.log(this.property1);
}
var instance = new MyClass("Hello world!");
instance.printProperty1(); // Prints hello world
To understand this code, you need to understand javascript's prototype-based inheritance model. When you create instance of MyClass, you get a new object that inherits any properties present in MyClass.prototype. Read more about it.
Also I wonder:
The function is a controller, and just declared once.
If you're not using this multiple times, you don't need to create something like class. You can do this instead:
var control = {doSomething:function() { ... }};
I assume you are used to Java, where everything must be a class, whether it makes sense or not. Javascript is different, you can also make single objects or functions as you need.

Overriding a function without removing static properties

If I have a function like this:
function a() {
console.log('a');
}
and then assign a static property like this:
a.static = 'foo';
But say I want to override the function with another function like this:
var old = a;
a = function() {
console.log('new');
old.call(this);
};
a.static // undefined
Since I assigned a new function to a, it’s static properties are lost. Is there a neat way to keep the static properties without looping and manually copying them?
Update:
Here’s a real world scenario: In Bootstrap jQuery plugins, the author assigns defaults to the property function like this:
$.fn.modal = function() {
// some code
};
$.fn.modal.defaults = { // some object };
So if I want to "extend" the prototype I would normally do:
var old = $.fn.modal;
$.fn.modal = function() {
// do my thing
old.apply(this, arguments);
}
But that would make
$.fn.modal.defaults === undefined
This will break the functionality, because the defaults are lost. I was wondering if there a sneaky way in javascript to change only the function without losing the static properties.
No, you cannot do this. Replacing the object (function) always takes any properties with it.
There are two solutions here, and both involve transferring the properties from the old object to the new one.
The first (recommended) approach is to copy the properties, which can be done conveniently with $.extend:
$.fn.plugin = $.extend(function() { ... }, $.fn.plugin);
The second option would be to dynamically set the prototype of the new function to be the old function. For example, in some browsers this would work:
var f = function() { ... };
f.__proto__ = $.fn.plugin;
$.fn.plugin = f;
However this is non-standard and might give rise to complications; don't do it.

Access child methods via parent class using this in dojo

Given class A and class B, where class B inherits from class A ...
// Define class A
dojo.declare("mynamespace.A",null,{
myMethodA: function() { this.myMethodB() }
});
// Define class B
dojo.declare("mynamespace.B",mynamespace.A,{
myMethodB: function() {}
});
Is it legal to call this.myMethodB() in the scope of class A (parent class)?
I have seen this in a piece of software and I do not understand it. I know that in Java, this is not possible unless you typecast A to B. But is dojo any different?
Your buzzword of this question would be this.inherited(arguments);
Your question goes for calling a method which is not in the current inheritance scope - and would by a true object oriented programmer be called invalid.. However it is possible (still) since the loader declared everything in global scope, e.g. you can access any module via mynamespace.X and then add prototype.theMethod.
Once you have inheritance as in mynamespace.B all of the functionalities of both A and B are 'this' scoped. It is simply like a merged hash of stuff, say for all methods and variables in A do set instance B[key] = property A[key].
However if you would encounter an override where the property is prototyped for both 'class' A and B - there is a mechanism in the declare / construct chain which allows for calling 'super' (or parent class, following your notation).
For the special property constructor it is allways so, that the inheritance bubbles[period].
For any methods that are declared only once, you cannot with respect of yourself call it if it is not an inherited method - and it will then be accessible via 'this'
For any methods which have overrides, the function 'this.inherited(arguments);' will send you upwards, one tick to the current parent class of callee. Look at the extended fiddle here
var AClass = dojo.declare("mynamespace.A", null, {
constructor: function(args) {
this.overriddenMethod();
},
overriddenMethod: function() {
}
});
var BClass = dojo.declare("mynamespace.B", [AClass], {
constructor: function() { },
overriddenMethod: function() {
// call super before anything else is processed in this method
// by placing following call you can control function callflow
this.inherited(arguments);
}
});
// will call A.constructor, then A.overriddenMethod
new AClass();
// will call B.constructor, A.constructor, B.overriddenMethod and then
// A.overriddenMethod via the call to super
// in B.overriddenMethod which A.constructor
// calls (note that A.constructor callflow 'aims' B.override not A.override)
new BClass();
There is no static compilation in JavaScript, therefore, as #akonsu has mentioned yet, it is technically possible, but it's not a pattern to follow:
var a = new mynamespace.A();
a.myMethodA(); // ilegal: Uncaught TypeError: Object [object Object] has no method 'methodB'
var b = new mynamespace.B();
b.myMethodA() // legal
You can also execute method/function in a given scope in JavaScript, i.e. as a method of given object:
a.myMethodA.call(b); // legal as `this` inside `myMethodA` will be referencing to object `b`
Practically, I think mynamespace.A may emulate abstract class with abstract method myMethodB as you know it from Java. Class mynamespace.A when subclassed, the subclass should implement myMethodB. But doing it this way is very error prone and I would do it in a more robust manner:
// Define class A
dojo.declare("mynamespaca.A", null, {
myMethodA: function() {
this.myMethodB();
},
myMethodB: function() {
// abstract method
console.warn("Abstract method [myMethodB] was not implemented.");
// or: throw new Error("Abstract method [myMethodB] was not implemented.");
}
});
// Define class B
dojo.declare("mynamespace.B", mynamespace.A, {
myMethodB: function() {
// implement abstract method here
}
});
You can call any method using the prototype object.
myMethodA: function() { mynamespace.B.prototype.myMethodB(); }
Here is a working example:
http://jsfiddle.net/cswing/7cBJm/

Convention for namespacing classes vs instances in javascript?

I am creating a instance of a class using the following code:
test = new function(){
...
}
However, base has no prototype because it was created from an anonymous function (I'm guessing this is the reason?). This leaves me unable to create any public functions for the instance.
You could argue I could get around this by simply doing:
function testClass(){
...
}
test = new testClass()
and then attaching public functions to testClass.
But this forces me to do unnecessary namespacing. In particular, if I were to name my class this.is.a.space, then what would I call my instance? this.is.a.spaceInstance? this.is.a.space.Instance?
Is there a convention for this sort of thing?
You can still code the anonymous function and use .__proto__ to access its prototype like this:
test = new function(){
...
};
test.__proto__.foo = function() { return 1 };
However, you only have one instance so you could also just use:
test.foo = function() { return 1 };
I'm not completely sure what exactly you're trying to accomplish, but as for the naming, it is usual to name the class like SomeClass and other variables (like instances) along the lines of someVariable. JavaScript is case-sensitive so you could use TestClass/testClass.

Better way to Dynamically Create New Objects in JavaScript?

I have two objects defined something like this (simplified for sake of the question):
var firstObject = function(){ };
firstObject.prototype.doSomethingFirstObjectsDo();
var secondObject = function(){ };
secondObject.prototype.doSomethingSecondObjectsDo();
Next I have an Object Manager which works as a sort of interface for my main application to create objects:
var ObjectManager = function()
{
this.create = {
FIRST:firstObject,
SECOND:secondObject
};
};
ObjectManager.prototype.createObject = function(type)
{
return new this.create[type]();
};
Finally an example of the main application using the Object Manager to Dynamically Create Either firstObjects or secondObjects:
var MainApplication = function(options)
{
this.objectTypes = options.objectTypes;
this.objManager = new ObjectManager();
};
MainApplication.prototype.createObjects = function()
{
//Iterate through all the types this application needs to create
for (var type in this.objectTypes)
{
var dynamicallyCreatedObject = this.objManager.createObject(type);
//Do Something Else
}
};
This approach works great, but has one disadvantage that I can see - being that you need to formally define the name of the Constructor Function for each Object "Type" that could be created.
In the event that I wanted to create a "thirdObject" - which would be already formally defined - I would also need to go back and add a reference to the "thirdObject"'s constructor function in the ObjectManager.
Ideally, I would like to remove the need for an "ObjectManager" and simply be able to dynamically call the constructor method with the "new" keyword like this:
//Inside MainApplication
for (var type in this.objectTypes)
{
var dynamicallyCreateObject = new [type](); //Invalid Syntax
};
Anybody have any thoughts on a better way to handle dynamically creating different objects in JavaScript using the "new" keyword?
Responding to Some Initial Comments:
I should have mentioned that the entire application is enclosed within an anonymous function.
(function(){
//All of My Mentioned Code is Found Here
$(document).ready(function(){
mainApp = window.mainApp = new MainApplication(options);
});
});
#casablanca: From what you are saying I believe I'll need to actually define a NameSpace inside the entire anonymous function, since once it finishes I have no real way to directly refer to that scope again. I think I know what I need to do now, I was kind of hoping there was another way to work with that "new" keyword - but it doesn't seem like that is the case.
This:
var dynamicallyCreateObject = new [type]();
is almost correct, except you need an outer object to access properties. In the case that your constructors are global, you can use window:
var dynamicallyCreateObject = new window[type]();
Ideally, they should be within your own namespace, in which case you can do something similar:
var dynamicallyCreateObject = new MyNamespace[type]();
Assuming I understand your desire (and I'm not sure that I do) you can use the global window object in DOM 0 browsers, or create your own reference to the global scope, and use that to look up variables defined locally.
var $global = this;
var firstObject = function(){};
var objName = "firstObject";
var instance = new $global[objName];

Categories

Resources