Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save JesterXL/4179932 to your computer and use it in GitHub Desktop.
Save JesterXL/4179932 to your computer and use it in GitHub Desktop.
Quick explanation of how to do classes + modules + privacy in JavaScript.
<html>
<head>
<title>JavaScript Classes</title>
</head>
<body>
<script src="libs/log4javascript/log4javascript_uncompressed.js"></script>
<script>
// setup logging
var logger = log4javascript.getLogger("RouterExample");
logger.setLevel(log4javascript.Level.ALL);
logger.addAppender(new log4javascript.BrowserConsoleAppender());
window.logger = logger;
logger.debug("index.html::log4javascript ready to rock.");
// Step 1: globals
logger.debug("*************************************************");
logger.debug("*** Step 1: Globals ***");
var myObject = {};
logger.debug("myObject: ", myObject);
logger.debug("window.myObject: ", window.myObject);
logger.debug("equal?: ", window.myObject == myObject);
// Step 2: local variables
logger.debug("*************************************************");
logger.debug("*** Step 2: local variables ***");
function init()
{
logger.debug("before...");
logger.debug("myObject: ", myObject);
logger.debug("equal?: ", window.myObject == myObject);
var myObject = {};
logger.debug("after...");
logger.debug("myObject: ", myObject);
logger.debug("equal?: ", window.myObject == myObject);
var myInnerObject = {};
}
init();
try
{
logger.debug("myInnerObject:", myInnerObject);
}
catch(e)
{
logger.error("myInnerObject can't be reached outside.");
}
// Step 3: Declarations
logger.debug("*************************************************");
logger.debug("*** Step 3: Declarations ***");
var myFunction = function()
{
logger.debug("before...");
logger.debug("myObject: ", myObject);
logger.debug("equal?: ", window.myObject == myObject);
var myObject = {};
logger.debug("after...");
logger.debug("myObject: ", myObject);
logger.debug("equal?: ", window.myObject == myObject);
var myDeclarationInnerObject = {};
}
myFunction();
try
{
logger.debug("myDeclarationInnerObject:", myDeclarationInnerObject);
}
catch(e)
{
logger.debug("myDeclarationInnerObject can't be reached outside.");
}
// Step 4: Globals via Function parameters
logger.debug("*************************************************");
logger.debug("Step 4: Globals via Function parameters");
var myGlobal = "imma global var";
function readSomeGlobals(aGlobal)
{
logger.debug("normal global reference via name, myGlobal:", myGlobal);
logger.debug("global reference via function parameter, aGlobal:", aGlobal);
logger.debug("aGlobal == myGlobal:", aGlobal == myGlobal);
}
readSomeGlobals(myGlobal);
// Step 5: Prototype classes with no privacy
logger.debug("*************************************************");
logger.debug("*** Step 5: Prototype classes with no privacy ***");
function SomeRandomClass(first, last)
{
this.firstName = first;
this.lastName = last;
}
SomeRandomClass.prototype.getName = function()
{
return this.lastName + ", " + this.firstName;
};
var instance = new SomeRandomClass("Jesse", "Warden");
logger.debug("instance:", instance);
logger.debug("instance firstName:", instance.firstName, ", lastName:", instance.lastName);
logger.debug("instance.getName():", instance.getName());
instance.firstName = "Cow";
logger.debug("I can change firstName to cow:", instance.getName());
logger.debug("Our class' constructor:", SomeRandomClass);
logger.debug("Notice, it's smack dab on window/global:", window.SomeRandomClass);
logger.debug("this is why people will fake C like #ifdefs to test if the class is defeined before defining it.");
// Step 6: Closure classes with privacy
logger.debug("*************************************************");
logger.debug("*** Step 6: Closure classes with privacy ***");
var ClosureClass = function(first, last)
{
var firstName = first;
var lastName = last;
return {
getName: function()
{
return lastName + ", " + firstName;
}
};
};
var closureInstance = new ClosureClass("Jesse", "Warden");
logger.debug("closureInstance:", closureInstance);
logger.debug("can't access private variable firstName: ", closureInstance.firstName);
logger.debug("However, it still exists via our internal getter method:", closureInstance.getName());
var secondClosureInstance = new ClosureClass("Bruce", "Campbell");
logger.debug("secondClosureInstance:", secondClosureInstance);
logger.debug("notice his name is different, and it's thus instance based, not static:", secondClosureInstance.getName());
logger.debug("Same problem, though... he's on global:", window.ClosureClass);
logger.debug("ClosureClass == window.ClosureClass:", ClosureClass == window.ClosureClass);
logger.debug("...thus requring yet another #ifdef... *face palm*");
// Step 7: Fun with closures (or an anonymous function that calls a function as its only paramter #lineOfCoke #lolWut) ***
logger.debug("*************************************************");
logger.debug("*** Step 7: Fun with closures (or an anonymous function that calls a function as its only paramter #lineOfCoke #lolWut) ***");
var myPackageOrModule = (function(){
var MySimpleObjectClass;
function MySimpleObjectClass(first, last)
{
setFirstName(this, first);
this.lastName = last;
}
function setFirstName(scope, newValue)
{
logger.debug("private setFirstName called, scope:", scope, ", newValue:", newValue);
scope.firstName = newValue;
}
MySimpleObjectClass.prototype.publicGetName = function()
{
return this.lastName + ", " + this.firstName;
};
return MySimpleObjectClass;
})();
try
{
logger.debug("privateGetFirstName:", privateGetFirstName);
}
catch(e)
{
logger.debug("notice we can't see the private function declaration, privateGetFirstName.");
}
logger.debug("myPackageOrModule:", myPackageOrModule);
logger.debug("Notice our actual class name can't be found, MySimpleObjectClass:", typeof MySimpleObjectClass == 'undefined');
logger.debug("Now, you CAN use MySimpleObjectClass as the return value. Here, it'll be put on global.")
logger.debug("But if used in another module, it won't... which is hot... and halfway there.");
var myModuleClassInstance = new myPackageOrModule("Jesse", "Warden");
logger.debug("myModuleClassInstance:", myModuleClassInstance);
logger.debug("myModuleClassInstance.publicGetName():", myModuleClassInstance.publicGetName());
try
{
myModuleClassInstance.setFirstName("Cow");
}
catch(privateError)
{
logger.debug("also, private doesn't work, heh, myModuleClassInstance.setFirstName('Cow'):", privateError);
}
var myModuleClassInstance2 = new myPackageOrModule("Mary", "Poppins");
logger.debug("myModuleClassInstance2:", myModuleClassInstance2);
logger.debug("just to show normal unique instances are supported, myModuleClassInstance2 and 1.publicGetName():", myModuleClassInstance2.publicGetName(), myModuleClassInstance.publicGetName());
// Step 8: Wrapping up, a closure example done the same way ***
logger.debug("*************************************************");
logger.debug("*** Step 8: Wrapping up, prototype and closure based classes via module pattern ***");
var theClosureClass = (function(){
var MySimpleClosureClass = function(first, last)
{
var closure;
var setFirstName = function(newValue)
{
logger.debug("private setFirstName called, scope:", closure, ", newValue:", newValue);
closure.firstName = newValue;
}
closure = {
firstName: null,
lastName: last,
getName: function()
{
return this.lastName + ", " + this.firstName;
}
};
setFirstName(first);
return closure;
};
return MySimpleClosureClass;
})();
logger.debug("theClosureClass:", theClosureClass);
var trueClosureInstance = new theClosureClass("Jesse", "Warden");
logger.debug("trueClosureInstance:", trueClosureInstance);
logger.debug("trueClosureInstance.getName():", trueClosureInstance.getName());
try
{
trueClosureInstance.setFirstName("Cow");
}
catch(privateErrorAgain)
{
logger.debug("Notice the closure retains his private method:", privateErrorAgain);
}
var trueClosureInstance2 = new theClosureClass("Kungfu", "Panda");
logger.debug("trueClosureInstance2:", trueClosureInstance2);
logger.debug("trueClosureInstance2.getName():", trueClosureInstance2.getName());
// Final note; to make a static, just return the object itself,
// remove the 'var MySimpleClosureClass = function(first, last)' part.
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment