I've sort if fell into this organization of javascript and was wondering if I'm missing the point somewhere here, or if there's a more elegant way of doing this.
Basically I'm wrapping everything in a function (object) and then setting up methods on that object, then instantiating an instance of the wrapper object and passing in any options and dependencies.
I have a hunch there's a way to automatically run .init() and a few other tweaks that could be made. Am I doing it right?
function AppModuleCore(){
var AppModuleCore = this; //keep internals sane
// Various global vars, objects
AppModuleCore.defaultOptions = {};
AppModuleCore.init = function(opts) {
// todo: that thing where you extend an options object a la juery
AppModuleCore.bindEvents();
};
AppModuleCore.bindEvents = function() {
// bind events here, send to functions within AppModuleCore.<FUNCTIONNAME>();
// Example:
$("a#clicker").unbind("click");
$("a#clicker").click(function(event){
AppModuleCore.handleClickerClick(event);
});
};
AppModuleCore.handleClickerClick = function(event){
alert("clicker was clicked");
};
}
// --------------------------------------------------------------------
// instantiate AppModuleCore object and initialize with opts,
// dependency injection
// --------------------------------------------------------------------
$(document).ready(function(){
AppModuleCore = new AppModuleCore;
var options = {};
AppModuleCore.init(options);
});
OK, some points
Having your code wrapped in a constructor only really makes sense if
You're going to instantiate more than one
You have "public" methods on the object that you are going to call
Your code doesn't exhibit these characteristics. I say this because your jQuery selectors a#clicker are hard coded so I'm assuming that you wouldn't want to bind the same events to them more than once?
You'd be better off using a function (perhaps your init) or an object literal to limit your scope..
function init( options ) {
var defaultsOptions = {};
var privateVar = 'only in this scope';
//extend your default options with options here
//using jquery
options = $.extend( defaultOptions, options );
// this function is completely private to this scope
function privatefunction() {
//do stuff
}
function handleClickerClick( event ){
alert("clicker was clicked");
}
// you don't need to wrap your handler in an anonymous function unless
// you're doing some work to the event before forwarding:- just give a
// reference to your handler
// the handler has access to other members of this scope, we're in a closure
$(options.selector).click( handleClickerClick );
//etc
}
init( {selector: 'a#clicker'} );
On a stylistic note: when you alias this with the same name as the constructor and then add methods to the alias, it looks at first glance like you are adding static methods to the constructor. This may be confusing to someone who looks at your code later and doesn't notice the alias.
function C() {
// a static method i.e a property of the constructor, C not objects created with it
// it is a bit wierd that it is defined in the constructor but not unheard of
C.staticMethod = function(){};
//quite plainly a method of objects of this type, easy to understand
this.method = function(){};
}
Related
I'm using the JavaScript Framework MooTools in which it is possible to create classes similar to Object-Orientation.
I dont know if it is somehow possible to alert the classname 'TestClass' within the class.
var TestClass = new Class({
Extends: Module,
initialize: function() {
//constructor which is called and should alert the Classname itself
alert(this.classname); (pseudocode)
}
});
Someone has an idea?
Thx in advance!
This is pretty easy as a workaround but a Class can be anonymous (like a function) and reflection is meaningless then.
Compare the(a) host object's enumerables with the instance's constructor. Not a cheap thing but still. Won't work very well if you use deep namespaces, for example: window.App.admin.controllers.view.Login since you'd need to either recursively look for it or know it's hosted by window.App.admin.controllers.view
// define the class in the current scope / global object
this.foo = new Class();
// directly into scope
var Foo = new Class();
// define the class in a namespace
var namespace = {
bar: new Class()
};
// get the variable class name we need to use from any source into a variable...
var dynamic = 'foo';
// make the instances
var instance1 = new this[dynamic]();
var instance2 = new namespace.bar();
var instance3 = new Foo();
function getClassNameOfInstance(mootoolsClassInstance, context) {
// query the context (this or custom object) for the instance we are working with
return Object.keyOf(context || this, mootoolsClassInstance.constructor);
}
// use it on the global object
console.log("instance1 is: ", getClassNameOfInstance(instance1)); // foo
// use it on the namespace object
console.log("instance2 is: ", getClassNameOfInstance(instance2, namespace)); // foo
// use it on the current scope.
console.log("instance3 is: ", getClassNameOfInstance.call(this, instance3)); // Foo
see it work here: http://jsfiddle.net/dimitar/c8pR4/
here is an example anonymous Class, a useful pattern if you don't plan on instantiating something more than once:
var instance = new (new Class({ ... }))(args);
I did write about this a while ago - http://fragged.org/working-with-dynamic-class-names-in-mootools_1395.html
A better / more sensible approach will be to manually give IDs to all Classes that need them, eg:
var Request.CORS = new Class('Request.CORS', { ... });
var i = new Request.CORS();
i.$className; // 'Request.CORS'
this is a pattern common in AMD (define('id', [deps], fn)), DOJO (declare('id', [deps], obj)) etc.
To extend your MooTools to support that you could do something like this:
http://jsfiddle.net/rnbW6/5/ - which will add a Request.JSON.prototype.$className property or getter (via Object.defineProperty config if avail).
If you go that route, you can even do a Class factory so your dependency resolution can be like Class.require('Request.CORS') and you won't ever need to save your definitions into global variables outside of the reference in your Class closure.
I want to keep my scripts organized in one .js file for all my site (I have a mess right now), something like namespaces and classes in C#...
(function ($) {
//private variables
$.divref = $("#divReference");
//Namespaces
window.MySite = {};
window.MySite.Home = {};
window.MySite.Contact = {};
//Public function / method
window.MySite.Home.Init = function(params){
alert("Init");
MySite.Home.PrivateFunction();
$.divref.click(function(){
alert("click");
});
};
//private function / method
MySite.Home.PrivateFunction = function(){
alert("Private");
};
})(jQuery);
Is this an idiomatic layout in jQuery and JScript?
I'll go ahead and post my comment as an answer, though I'm not 100% it addresses your questions about c# namespaces and their parallels in JavaScript (I'm no c# programmer). You're not actually creating private variables because you're attaching them to the $ Object that will exist after this function finishes. If you want private variables you need to use a closure. Those look something like this:
var myObject = function () {
var innerVariable = 'some private value';
return {
getter: function () {
return innerVariable;
}
}
}()
If you attempt to access myObject.innerVariable it will return undefined but if you call myObject.getter() it will return the value correctly. This concept is one you will want to read up on in JavaScript, and for programming in general. Hope that helps.
This is more how I would implement the pattern you are trying to do:
// MySite.Home Extension
window.MySite =
(function ($, root) {
//private variables
var $divref = $("#divReference");
//private function / method
var privateFunction = function(){
alert("Private");
};
root.Home = {};
// Public variable
root.Home.prop = "Click"
//Public function / method
root.Home.Init = function(params){
alert("Init");
private();
$divref.click(function(){
alert(root.Home.prop);
});
};
return root;
})(jQuery, window.MySite || {} );
// MySite.Contact Extension
window.MySite =
(function ($, root) {
root.Contact = {};
// More stuff for contact
return root;
})(jQuery, window.MySite || {} );
The first change is splitting each "namespace" into its own Module pattern, so private variables wont bleed from namespace to namespace (if you do intend them to be private to the namespace, which would be more C# esque). Second is rather than accessing window.MySite, pass in the object that you want to extend (in this case I'm calling it root). This will give you some flexibility.
Your private methods weren't really private. To make a private method, you just want to make a function var that it bound in the closure, but not assigned to a property on the externally visible object. Lastly, you probably don't want to use $.somegarbage. Like mentioned in a comment, you are adding a property to the $ object, which will still be there when the closure is done. If you wanted something close, I would just use $somegarbage which some people seem to like to do, but any variable name will work for private variables, just as long as the variable is bound in the closures scope (not somewhere else)
You are on the right track...
you might want to read up on the Module pattern (more) and closures in javascript to prevent polluting the global namespace.
This is more of an exploratory question, seeing how the core JavaScript stuff works. I realize the convention is to not override any core JavaScript classes, but I just can't seem to wrap my head around this one.
You can create what acts like "class methods" in JavaScript by adding to the core Function prototype like this:
Function.prototype.class_method = function() {
console.log("class method called")
}
var User;
User = (function() {
function User() {}
return User;
})();
User.class_method(); // "class method called"
My question is, is there a way to add "instance methods" in a similar way? Something crazy like this, but what's below doesn't work (or make any sense):
alias = Function.prototype.constructor;
Function.prototype.constructor = function() {
child = this;
child.prototype.instance_method = function() {
console.log("instance method called");
}
alias.apply(child);
}
var user = new User();
user.instance_method(); // method doesn't exist
It's almost like you'd need to override the Function class' constructor method and access the prototype from there. Is this possible?
It does work if you add to the Object.prototype like this:
Object.prototype.instance_method = function() {
console.log("instance method");
}
var user = new User();
user.instance_method(); // "instance method called"
But that doesn't seem right either, mainly because seeing the output in the node.js console from console.log({}); change is confusing:
console.log({});
// {};
Object.prototype.instance_method = function() {
console.log("instance method");
}
console.log({});
// {"instance_method": [Function]}
If you are using node.js, you should be able to use Object.defineProperty [MDN] and make the new property non-enumerable:
Object.defineProperty(Object.prototype, 'instance_Method', {
value: function() {
console.log("instance method");
},
enumerable: false // it's already the default
});
This was introduced in ECMAScript5, so only newer browsers will support it.
It's important to understand when the prototype comes into play. It's simply an object that is a property of a function. It only has meaning when you use the new keyword. Example:
var Widget = function(val) {
this.value = val;
};
Widget.prototype.getValue = function() {
return this.value;
};
var widget1 = new Widget('test');
widget1.getValue(); // test
var widget2 = new Widget('test2');
widget2.getValue(); // test2
When new is used, the js interpreter will create a hidden _proto_ property on the instance. This proto link is simply a reference to the prototype object of the constructor function, e.g., Widget at the time the constructor was called.
When you override the Function constructor, you are literally adding something that will be on the _proto_ property of every function created after you modified Function.prototype.
If you make the statement child.prototype... = ... in your base 'class' constructor function, then that prototype will not have meaning until something 'instantiates' child, e.g., var child = new child();.
A great Resource.
To answer your question about 'instance methods', you simply need to do something like the following:
var Widget = function() {
this.method = function() {
return 'instance method';
};
};
Widget.prototype.method = function() {
return 'class method';
};
var widget1 = new Widget();
widget1.method(); // instance method
delete widget1.method;
widget1.method(); // class method
This is due to javascript's implementation of Prototypical Inheritance. The proto link I spoke of before is key here. When widget1 was first created, inside the constructor function Widget, method was attached specifically to widget1. This method will not be available to other instances. However, method on the prototype is shared across all instances of Widget.
At runtime, when the js interpreter sees widget1.method();, it first sees if widget1 has method as a property directly on it (objects in js are just hashmaps in essence, in which the keys are called 'properties'). It finds the instance method as a property in this case. However, once you delete the instance method, it will attempt to follow the _proto_ link, which is just an object reference to Widget.prototype (at the time the constructor was called). Widget.prototype.method is defined; therefore, the interpreter will execute that. If no method function is found when continuing to follow _proto_ links, it'll be a run-time error.
Hi I don't know whether this is my mistake in understanding Javascript prototype object ..
Well to be clear I'm new to the Javascript singleton concept and lack clear cut knowledge in that but going through some referral sites I made a sample code for my system but it's giving out some errors which I couldn't find why so I'm asking for your help. My code is:
referrelSystem = function(){
//Some code here
}();
Prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
I get an error saying prototype is undefined!
Excuse me i thought of this right now
EDIT
I have used like this:
referrelSystem = function(){
return{
login:getSignedIn,
initTwitter:initTw
}
};
Is this causing an issue?
A typical way to define a JavaScript class with prototypes would be:
function ReferrelSystem() {
// this is your constructor
// use this.foo = bar to assign properties
}
ReferrelSystem.prototype.postToFb = function () {
// this is a class method
};
You might have been confused with the self-executing function syntax (closures). That is used when you would like to have "private" members in your class. Anything you declare in this closure will only be visible within the closure itself:
var ReferrelSystem = (function () {
function doSomething() {
// this is a "private" function
// make sure you call it with doSomething.call(this)
// to be able to access class members
}
var cnt; // this is a "private" property
function RS() {
// this is your constructor
}
RS.prototype.postToFb = function () {
// this is a class method
};
return RS;
})();
I would recommend that you study common module patterns if you're looking into creating a library.
Update: Seeing your updated code, the return from referrelSystem won't work as expected, since return values are discarded when calling new referrelSystem().
Rather than returning an object, set those properties to this (the instance of referrelSystem that gets constructed):
var referrelSystem = function () {
// I assume you have other code here
this.login = getSignedIn;
this.initTwitter = initTw;
};
I don't think you intend to immediately execute the functions, change them to this:
var referrelSystem = function(){
//Some code here
};
(+var, -())
Same with the prototype function:
referrelSystem.prototype.postToFb = function(){
//Some Code here
};
(Here you don't need the var, because you're assigning to something that already exists.)
A function should return to work as
prototype
property.
Take a look at this example here
I want to create a plugin called 'myPlugin'. Which method should I use and what is the difference between these two methods? Please tell me the advantages too. I am from designing background and not much programming knowledge.
var myPlugin = {
myId:"testId",
create:function(){},
destroy:function(){}
}
OR
function myPlugin() {
this.myId = "testId";
this.create = function(){};
this.destroy = function(){};
}
The first method creates a singleton object, stored in a variable called myPlugin. Only one instance of the "plugin" exists in this form. If you know you will only need one instance, this approach is a good choice. You can also extend its capabilities to allow for both public and "private" properties by using the Module Pattern.
The second method defines an object constructor function, which will allow you to make multiple instances of the object using the new keyword. This will allow you to use as many copies of the object as you might need, and sets you up with the ability to add onto the object using its prototype.
I would go for something like:
function myPlugin () {
this.myId = "testId";
this.create = createFunction;
this.destroy = destroyFunction;
}
function createFunction() {
alert('createFunction() called');
}
function destryFunction() {
alert('destroyFunction() called');
}
my plugin = new myPlugin();