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];
Related
Are there any (non-trivial/ugly hack) ways to call a 'private' method from outside a class/module itself?
Please don't ask why I need this.
Just my personal curiosity and trust in power of doing anything in JS :)
function Module () {
var privateMethod = function () {
alert('1');
};
var publicMethod = function () {
privateMethod();
alert(2);
};
return {
pm: publicMethod
};
}
var m = new Module();
m.pm(); // can i call m.privateMethod() here somehow?
DON'T TRY THIS AT HOME
So you've been warned, now look at this (fiddle; I've replaced all the alerts with console.log() for the greater good):
var methodName = 'privateMethod';
var mSource = Module.toString();
var methodPattern = new RegExp(methodName + '\\s*=\\s*function[^]*?\\{([^]+?)\\};');
var privateMethodSource = mSource.match(methodPattern);
var privateMethodRebuilt = new Function([], privateMethodSource[1]);
privateMethodRebuilt();
It's one possible way to do this with HUGE number of restrictions. First, this particular snippet doesn't even try to parse the arguments, assuming that the method in question doesn't need any. Second, you won't be able to access the other private variables defined within the Module (as the code rebuilds only the particular function, not the environment).
Surely, you can take it further - and rebuild the Module itself, making the target method public (for example, by adding the private function into the exposed methods' list). The question is, WHY on Earth do you even think about needing such thing as using the private method outside the module?
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.
I have a function on a prototype like this:
Car.prototype.drive = function() {
this.currentSpeed = this.speed;
}
I want to call this function very often in another function which is also part of the prototype Car. And because I'm lazy I don't want to rewrite the this all the time. So I would like to copy a reference to the function to a local variable:
Car.prototype.doSomeThing = function() {
var driveReference = this.drive;
driveReference();
}
But when I call driveReference(), the this-pointer of driveReference() points to Window instead to my instance of Car.
Is there any possibility to prevent that?
(apply() would work, but that is even more verbose then using this)
You can use Function.prototype.bind to bind the context of a function to whatever you like:
Car.prototype.doSomeThing = function() {
var driveReference = this.drive.bind(this);
driveReference();
}
You could write
var driveRef = this.drive.bind(this);
but that can have some possibly unwanted performance impact. Or you could just copy this to a shorter variable name:
var me = this;
me.drive();
Explicitly using a reference to the context object is a pretty basic design feature of JavaScript, so it's hard to get around it.
First of all, I'm attempting to use faux namespaces in my JavaScript program like so:
// Ish.Com namespace declaration
var Ish = Ish || {};
Ish.Com = Ish.Com || {};
// begin Ish.Com.View namespace
Ish.Com.View = new function() {
var privateVariable;
this.publicFunction = function() {
this.publicFunction2()
};
this.publicFunction2 = function() { ... };
};
I'm not crazy about using this to call other functions, but up to recently, it has worked. However, I've added event listeners to some elements, and they interpret this to be the target object.
I know I can use the full namespace instead of this to call functions inside of my listeners (Ish.Com.View.publicFunction2()), but the listeners often call one function, which calls another, and another. I'd need to use the entire namespace in nearly every function call.
How can I get namespaces to work nicely with Event Listeners? I'd also be interested in a better way of implementing namespaces, since using this.publicFunction2() is clunky.
I'm very interested in best-practices, and learning how to write a well architected application in JavaScript. However, frameworks are out of the question until I gain a more thorough understanding of JavaScript.
Seems like I've been answering every question this morning the same way :-)
You can use ".bind()":
var eventHandler = yourObject.someFunction.bind(yourObject);
That'll guarantee that this will refer to "yourObject" whenever the "eventHandler" is called by anything.
The "bind()" function is there on the Function.prototype object in newer browsers. The Mozilla docs include a solid implementation of "bind()" you can use to patch older browsers.
What "bind()" does is return you a new function that explicitly arranges for this to be bound as you stipulate. You can also pass arguments to be passed in, if you like. An alternative to using "bind()" is to wrap the function call in your own anonymous function:
var eventHandler = function() { yourObject.someFunction(); };
I don't know if i have understood completely your question.
Would this suit your needs ?
var obj = new function() {
var scope = this;
this.fun1 = function() {
return scope.fun2();
}
this.fun2 = function() {
//do sth
}
};
This is caused by variable context and closure. "this" always refers to the current object. The event function is an object itself and "this" refers to that object. If you need to refer to the parent object you can use bind as described previously or you set the parent "this" to a variable and use that in your event function.
// Ish.Com namespace declaration
var Ish = Ish || {};
Ish.Com = Ish.Com || {};
// begin Ish.Com.View namespace
Ish.Com.View = new function() {
var privateVariable, thisObj=this;
this.publicFunction = function() {
thisObj.publicFunction2()
};
this.publicFunction2 = function() { ... };
};
I am trying to localize everything to a namespace in javascript. So I have objects that follow a naming convention like:
myapp.utilities.file.spinner
etc...
My question is, is there a way to avoid repeating that big string everytime I want to augment the object with a property or a method. Currently my code looks like this...
myapp.utilities.file.spinner.method1 = function() { };
myapp.utilities.file.spinner.method2 = function() { };
etc.
Something like this...
spinnerPath.method1 = function()
...where spinnerPath stands for myapp.utilities.file.spinner, would be nicer. But from my understanding I cannot just say
spinnerPath = myapp.utilities.file.spinner
as that will create another object in the global space.
Thanks
The code you're using won't actually create a new object, merely a new global variable referring to the existing object. It will pollute the global namespace however, so if you're looking to avoid that, you have several options:
You can use with, but don't because it will probably cause you more heartache than it's worth.
You can make a shorthand pointer variable inside each function outside of the global namespace: var s = myapp.utilities.file.spinner;, but this is annoying.
(Probably the best option) create a "private namespace" using an immediate-call function:
(function (S)
{
S.method1 = function(){/*whatever*/};
S.method2 = function(){/*whatever*/};
})(myapp.utilities.file.spinner)
Try this:
(function(){
var spinner = myapp.utilities.file.spinner;
spinner.method1 = function(){};
})();
myapp.utilities.file.spinner.method1 = function() { };
myapp.utilities.file.spinner.method2 = function() { };
...
// Somewhere else in your code, create a temp local called "spinner"
// that references your longer path object.
var spinner = myapp.utilities.file.spinner;
spinner.method1();
You can just make a temporary local variable wrapped in an anonymous function:
(function(){
var spinnerPath = myapp.utilities.file.spinner;
spinnerPath.method1 = function() { };
spinnerPath.method2 = function() { };
spinnerPath.method1();
})();
Here, spinnerPath is in fact a local reference to the global myapp.utilities.file.spinner object, not a copy. Objects in JavaScript are references, so if you create a local variable that points to it, you will not create a copy or pollute the global namespace.