I'm creating a game engine, or more like a large library of useful classes and functions, for Javascript. I plan to use it both for some scientific simulations on the server side and on the client side, so the spectrum of functionality will be quite broad, but always it will revolve around a virtual world (a game, for example).
I'm not sure how to wrap it up, though. If I just provide all the classes, it would pollute the global namespace, which is quite bad. Can I just place everything inside one object, that acts as a namespace? Should the framework itself be a class that can be instanced?
If the later option is chosen, how do I handle classes inside classes (constructor functions)?
var Engine = function()
{
this.someVar = 4;
}
Engine.prototype.Scene = function()
{
this.entities = [];
//What if the scene object needs some classes that are in the engine? How does it get it's parent engine object?
}
Engine.prototype.Scene.prototype.render = function()
{
//"this" should now represent an instance of a scene. But how can I get someVar from the engine? How can I traverse up in the hierarchy of classes?
}
I prefer to use what's sometimes called a "revealing module" (... pattern). It looks like:
var Engine = (function($)
{
$ = $ || {};
var someVar = 4;
$.Scene = function()
{
this.entities = [];
}
$.Scene.prototype.render = function()
{
// this function can access someVar just fine because of JavaScript's scoping rules
}
return $;
})(Engine);
This uses what's called an immediately-invoked function expression (hereafter referred to as an IIFE) to form a closure within the Engine object. Due to JavaScript's handling of scope, someVar is accessible to any function defined within the IIFE. The implication, however, is that no function can define it's own someVar if it wants to refer to the someVar you define in the IIFE.
The magic comes from the return statement. You can see that an object is returned, and within this object you must define anything you want to be "public".
The constructors, utility methods, etc. can then be accessed via Engine.Scene, which nicely namespaces your code.
As for the $ argument, this is so that you can pass Engine to the function in each file, add some methods/properties/constructors (or create a new one if it doesn't exist) and then pass the return value to another IIFE for further expansion.
This is the method used in many popular JavaScript frameworks including jQuery, dojo and LimeJS
scene.js:
var Engine = (function ($) {
// this creates a new object if Engine is undefined in the
// invocation below, and keeps the old object otherwise.
// alternatively: if ($ === undefined) { $ = new Object; }
$ = $ || {};
$.foo = "foo";
$.Scene = function () {
// blah blah
}
// Engine holds either a newly created object,
// or the old one if it was already defined
return $;
})(Engine);
sprite.js:
var Engine = (function ($) {
$ = $ || {};
$.Sprite = function () {
// totally works
this.bar = $.foo;
}
return $;
})(Engine);
You can then use them with something like:
<script type="text/javascript" src="bar.js"></script>
<script type="text/javascript" src="foo.js"></script>
<script type="text/javascript">
var mySprite = new Engine.Sprite;
var myScene = new Engine.Scene;
</script>
You can substitute $ with whatever you like, $$ is common, or you can be clever. It's just a placeholder for the global object you're adding on to.
I don't think you need or even should organize your classes like that. Even though the Scene and Engine classes are related, the Scene class doesn't have to be a children of Render. Use a flat class hierarchy instead, that will be easier to maintain and scale.
Finally, you should indeed put all these classes under the same namespace so as not to pollute the global namespace.
// Define the namespace only if it doesn't already exist. That
// way you can split the definition of your classes in various
// files, without having to worry in which order they are loaded.
if (typeof gameEngine === 'undefined') gameEngine = {};
gameEngine.Engine = function()
{
this.someVar = 4;
}
gameEngine.Scene = function()
{
this.entities = [];
}
// Add a new function to define which
// scene the Engine should render:
gameEngine.Engine.prototype.setScene = function(scene)
{
this.scene = scene;
}
gameEngine.Engine.prototype.render = function()
{
// render this.scene
}
Related
I have a bunch of extension methods of String and other JavaScript types, they now reside in global namespace.
What is the best practice to organize those extension methods? Should I encapsulate them inside a namespace? If yes, how to achieve that? Thanks!
Namespace your JavaScript if you need to refer to it elsewhere.
// define your global namespace
var Extensions = Extensions || {};
// add modules to it
Extensions.String = function() {
var myPrivateProperty = 2;
var myPublicProperty = 1;
var myPrivateFunction = function() {
console.log("myPrivateFunction()");
};
var myPublicExtension = function() {
// this extension is being called, now what?
console.log("myPublicExtension()");
};
// this object will be returned, giving access to public vars/methods
return {
myPublicProperty: myPublicProperty,
myPublicExtension : myPublicExtension
};
}();
console.log("Calling myPublicExtension()...");
Extensions.String.myPublicExtension();
Anonymously scope JavaScript if you’re never going to call it elsewhere.
// This will keep your namespace clean
(function() {
// here you can define your modules, functions, etc..
var x = 123;
console.log(x);
// to make something global you can define it like
window.globalVar = 5;
}());
Or you can extend the native javascript objects with prototype like this:
String.prototype.myExtension = function(p1, p2) {
// here is your function
return this + p1 + p2;
}
This way you don't need to define namespaces and you can call your extensions directly from any object you extended:
var otherString = "mystring".myExtension(" is", " great!");
console.log(otherString);// mystring is cool
you can do that with any object in javascript
EDIT:
Prototype extensions don't pollute global namespace, because they are accesible only through the object you extended.
If you have many extensions consider taking them into a file like extensions.js, then add it to your pages whenever you need those extensions. This way extensions.js can be cached by the browser and will be loaded faster
There are 2 ways of doing that:
Encapsulating in a namespace (I think the bare minimum to keep things tidy). A custom namespace ie:
window.MyNameSpace.trim = function(str) {
return str.replace(/^\s+|\s+$/g, "");
}
(replace MyNameSpace with a single letter! R for Raphael, L for Leaflet, etc)
Extend prototypes! Lots of people will disagree with that but I see no harm if it is your site and you don't override/conflict with anyone else code:
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, "");
};
I find this "cleaner" since you don't pass unnecessary arguments around... but again, it is a matter of opinion... This will work for any build-in type. The rest I think should follow #1
DISCLAIMER: Code from This post
How do I properly communicate data betweens two scripts.
In this particular case I have an element in one script, but I want to append it in another script.
The simplest way I could do this is by using the global window object as go-between.
But globals are not best practice.
What is the correct way to pass this element to another script?
Both script are encapsulated in the module pattern.
Script 0 Create Element Point
var element = document.createElement( "div" );
element.innerHTML = response_text;
Script 1 Append Element Point
Vi.sta = {
// implemented in the boot loader - shared global space - appended child already - you don't have to append until now.
// Static data has already been composed.
// Pull off window and append or best practice
};
Both are encapsulated in the module pattern
(function(){
// the code here
})()
All JS scripts are run in the global scope. When the files are downloaded to the client, they are parsed in the global scope.
So if you've got
// File_1.js
var myObj = { colour : "blue" };
There's nothing stopping you from doing this:
// File_2.js
var otherObj = { colour : myObj.colour };
As long as File_1.js is loaded before File_2.js
If you are namespacing, ie: MYNAMESPACE = {}; and each file extends your namespace through modules (rather than "module pattern" referring to returning interfaces from immediately-invoking functions), then check for the module's existence.
If you ARE writing modules for a namespaced app, and you DO need access to variables from one module to another, then you should be providing an interface for that.
If you are SANDBOXING modules, then you need to provide them all a proxy similar to a service-locator or a "registry", or develop a messaging-system based on a mediator-pattern.
window.sharedSpace = {};
sharedSpace.sharedValue = 'foo bar';
That way you only have one global object instead of several.
Why don't you just pass the element to a function in the module?
var module1 = (function () {
return {
func1: function () {
// get your element
var someElement = ...;
// pass it to the other module
module2.func2(someElement);
}
};
}) ();
var module2 = (function () {
return {
func2: function (someElement) {
// do whatever you want with someElement
}
};
}) ();
I'm trying to write 'better' javascript.
Below is one pattern I've found, and am trying to adopt. However, I'm slightly confused about its use.
Say, for example, I've got a page called "Jobs". Any JS functionality on that page would be encapsulated in something like:
window.jobs = (function(jobs, $, undefined){
return {
addNew: function(){
// job-adding code
}
}
})(window.jobs|| {}, jQuery);
$(function(){
$('.add_job').on('click', function(event){
event.preventDefault();
window.jobs.addNew();
});
});
As you can probably deduct, all I've done is replaced all the code that would have sat inside the anonymous event-handler function, with a call to a function in my global jobs object. I'm not sure why that's a good thing, other than it's reduced the possibility of variable collisions and made the whole thing a bit neater, but that's good enough for me.
The - probably fairly obvious - question is: all my event-binding init-type stuff is still sitting outside my shiny new jobs object: where should it be? Inside the jobs object? Inside the return object inside the jobs object? Inside an init() function?
I'm just trying to get a sense of a stable, basic framework for putting simple functionality in. I'm not building JS apps, I'd just like to write code that's a little more robust and maintainable than it is currently. Any and all suggestions are warmly welcomed :)
You can break down your application in whatever number of modules / objects you like too.
For instance, you can have another object / module which caches and defines all your DOM nodes and another one, which just handles any event. So for instance:
(function ( win, doc, $, undef ) {
win.myApp = win.myApp || { };
var eventHandler = {
onJobClick: function( event ) {
event.preventDefault();
myApp.addNew();
}
};
var nodes = (function() {
var rootNode = $( '.myRootNode' ),
addJob = rootNode.find( '.add_job' );
return {
rootNode: rootNode,
addJob: addJob
};
}());
$(function() {
myApp.nodes.addJob.on( 'click', myApp.handler.onJobClick );
});
myApp.nodes = nodes;
myApp.handler = eventHandler;
}( this, this.document, jQuery ));
It doesn't really matter how you create singletons in this (module) pattern, either as literal, constructor, Object.create() or whatnot. It needs to fit your requirements.
But you should try to create as many specific modules/objects as necesarry. Of course, if makes even more sense to separate those singletons / modules / objects into multiple javascript files and load them on demand and before you can say knife, you're in the world of modular programming patterns, dealing with requireJS and AMD or CommonJS modules.
Encapsulation-wise, you're fine: you could even just declare addNew in the jQuery closure and you'd still avoid the global scope. I think what you're getting at is more of implementing something close to an MVC architecture.
Something I like to do is create an object that you instantiate with a DOM element and that takes care of its own bindings/provides methods to access its controls etc.
Example:
// (pretend we're inside a closure already)
var myObj = function(args){
this.el = args.el; // just a selector, e.g. #myId
this.html = args.html;
this.bindings = args.bindings || {};
}
myObj.prototype.appendTo = function(elem){
elem.innerHTML += this.html;
this.bindControls();
};
myObj.prototype.remove = function(){
$(this.el).remove(); // using jQuery
};
myObj.prototype.bindControls = function(){
for(var i in this.bindings){ // event#selector : function
var boundFunc = function(e){ return this.bindings[i].call(this,e); };
$(this.el).on(i,boundFunc);
}
};
The way you are doing it right now is exactly how I do it also, I typically create the window objects inside the anonymous function itself and then declare inside that (in this case: jClass = window.jClass).
(function (jClass, $, undefined) {
/// <param name="$" type="jQuery" />
var VERSION = '1.31';
UPDATED_DATE = '7/20/2012';
// Private Namespace Variables
var _self = jClass; // internal self-reference
jClass = window.jClass; // (fix for intellisense)
$ = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense)
// I init my namespace from inside itself
$(function () {
jClass.init('branchName');
});
jClass.init = function(branch) {
this._branch = branch;
this._globalFunctionality({ globalDatePicker: true });
this._jQueryValidateAdditions();
//put GLOBAL IMAGES to preload in the array
this._preloadImages( [''] );
this._log('*******************************************************');
this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE);
this._log('*******************************************************\n');
};
jClass._log = function() {
//NOTE: Global Log (cross browser Console.log - for Testing purposes)
//ENDNOTE
try { console.log.apply(console, arguments); }
catch (e) {
try { opera.postError.apply(opera, arguments); }
catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ }
}
};
}(window.jClass= window.jClass|| {}, jQuery));
The reason I leave them completely anonymous like this, is that let's say in another file I want to add much more functionality to this jClass. I simply create another:
(function jClass, $, undefined) {
jClass.newFunction = function (params) {
// new stuff here
};
}(window.jClass = window.jClass || {}, jQuery))
As you can see I prefer the object.object notation, but you can use object literals object : object, it's up to you!
Either way by leaving all of this separate, and encapsulated without actual page logic makes it easier to have this within a globalJS file and every page on your site able to use it. Such as the example below.
jClass._log('log this text for me');
You don't want to intertwine model logic with your business logic, so your on the right path separating the two, and allowing for your global namespace/class/etc to be more flexible!
You can find here a comprehensive study on module pattern here: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html It covers all the aspects of block-scoped module approach. However in practice you gonna have quite a number files encapsulating you code, so the question is how to combine them property. AMD... multiple HTTP requests produced by every module loading will rather harm your page response time. So you can go with CommonJS compiled to a single JavaScript file suitable for in-browser use. Take a look how easy it is http://dsheiko.github.io/cjsc/
I'm using the javascript module pattern, and have this so far:
var APP;
if(APP == undefined) {
APP = {};
}
APP = (function() {
var userId = -1;
var privateVar = '';
var _init = function($userId) {
userId = $userId;
};
var _publicMethod = function($id){
privateVar = id;
};
return {
init = function($userId) {
_init($userId);
},
publicMethod = function($id) {
_publicMethod($id);
}
};
})();
I then have a common utils module:
APP.utils = (function(){
})();
And then per page I am planning on having a module, so I don't wireup events (button clicks etc) for no reason on pages where these DOM elements don't event exist:
APP.homePage = (function(){
return {
};
})();
So each module will have a init() method that I will call on the page to run things that have to be run (e.g. wiring up events, setting variables like say userId etc):
$(document).ready(function() {
APP.init(<%= user.id %>);
APP.homePage.init('abc');
});
So now if the files get too big, I can break them out into separate files also.
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
How is my coding style, any obvious style that is not considered best practise?
Any comments on this approach? Is it good in general?
What if one module needs to call another, I guess the only way for this to work is to do this via the public api right?
Yes
e.g. what if homePage needs userId, should I pass that in the homePage#init method?
No. I'd not repeat the userId code in all modules, but offer a public getter for it in the default module.
Any comments on coding
This code
var APP;
if(APP == undefined) {
APP = {};
}
APP = ...
is quite useless. You don't need to check for object existance here, because you overwrite it anyway. That also means that this code must be the first to execute. If you want to make the modules independent from load order, you'd need to use something like
var APP = (function(a) {
var private_vars; // ...
a.init = ...
a.publicMethod = ... // add them to the object instead of creating new one
a.getPrivate = function() {
return private_vars;
};
return a;
})(APP || {}); // create one iff not already existing
// other file:
var APP = APP || {};
APP.utils = ... // add object to namespace
The code
var _publicMethod = function($id){
privateVar = id;
};
looks a bit odd. First, the underscore usually denotes a semiprivate (public-but-not-to-be-used) attribute of objects and should not be used for variable names. That's not the case in here as the function will be exposed as the "publicmethod" property of APP. Use the underscore there if you want it. Second, there is no need to use a function expression here. The code is in the module's local scope, and using a function declaration both makes it available everywhere in that scope and allows naming the function. You should use
function publicMethod($id) {
privateVar = id;
}
a.publicMethod = publicMethod;
The module pattern is, in my opinion, a really nice way to organize your code. To answer your questions:
1) Yes, your modules can only access methods and properties of other modules which have been exposed in the object they return.
2) I think your coding style looks pretty good. I'd make these changes:
APP = (function() {
var _userId = -1;
var _privateVar = '';
var init = function($userId) {
_userId = $userId;
};
var publicMethod = function($id){
_privateVar = id;
};
return {
init : init,
publicMethod : _publicMethod
};
})();
First, underscores are generally meant to denote "private" properties or methods. Secondly, you can do away with the extra functions in the object being returned and just point straight to the methods or properties you care about. This is generally referred to as the "Revealing Module Pattern", because even the public methods aren't defined within the returned object - they're simply referenced.
3) This approach is definitely a nice way to encapsulate code. You get the benefit of private and privileged methods, and you generally end up with a nicer API because you're only exposing things that need to be public.
Well done.
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.