Skip to content

Instantly share code, notes, and snippets.

@widged
Last active August 29, 2015 14:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save widged/a000c723065d05659a3d to your computer and use it in GitHub Desktop.
Save widged/a000c723065d05659a3d to your computer and use it in GitHub Desktop.
// Person Module
var Person = (function ( ) {
'use strict';
// Any static variable can be declared here.
var Class = function Person() {
if(!this instanceof Person) { return new Person(); }
var instance = this;
// Private variables and functions that only
// ..other private or public functions may access
// ..and cannot be accessed outside this Module
var age = 0,
maxAge = 30,
maxWeight = 80,
isAlive = true,
weight = 20,
name = 'Un-named';
function growOld() {
if ( age++ >= maxAge ) {
die();
}
}
function gainWeight() {
weight++;
if ( weight >= maxWeight ) {
die();
}
}
function loseWeight() {
weight--;
if ( weight <= 0 ) {
die();
}
}
function die() { isAlive = false; }
// All the properties and methods attached to `instance`
// will be public and will be accessible in the global scope.
// Public Accessors
instance.name = function(_) {
if(!arguments.length) { return name; }
name = _;
return instance;
}
instance.age = function(_) {
if(!arguments.length) { return age; }
if(_ > maxAge && age < 0) { throw 'illegal age value' }
age = _;
return instance;
}
instance.weight = function(_) {
if(!arguments.length) { return weight; }
if(_ > maxWeight && weight < 0) { throw 'illegal weight value' }
weight = _;
return instance;
}
// Public Methods
instance.speak = function () {
if ( !isAlive ) {
alert('Dead man can\'t speak.');
} else {
alert('Speaking...');
growOld();
}
return instance;
},
instance.walk = function () {
if ( !isAlive ) {
alert('Dead man can\'t walk.');
} else {
alert('Walking...');
growOld();
loseWeight();
}
return instance;
},
instance.eat = function () {
if ( !isAlive ) {
alert('Dead man can\'t eat');
} else {
alert('Eating...');
gainWeight();
}
return instance;
}
instance.toString = function() {
return '' + Class.name + ' ' + JSON.stringify({name: name, age: age, weight: weight});
}
return instance;
}
return Class;
}());
var bill = new Person().name('Bill').age(40).weight(30);
console.log(bill.eat().weight())
console.log(bill.walk().age())
console.log(bill.toString())
@widged
Copy link
Author

widged commented Jan 5, 2015

Motivations for differences with the code shown at http://kamranahmed.info/blog/2015/01/03/private-and-public-scopes-in-javascript/ are:
(1) Introducing an instance variable let me write functions the normal way. I don't need a different syntax for private and public functions, which makes it slightly easier when refactoring.
(2) Introducing an instance variable provides support for a chainable interface var bill = new Person().name('Bill').age(40).weight(30);. The convention then is for any function that doesn't return a value to return the instance.
(3) Opting for Class = new FactoryName() creates a factory that creates typed instanced (try console.log(new Person())).
(4) Wrapping the code into a module (IIFE, AMD, or Commonjs) protects against global scope pollution
(5) The extra module level gives an opportunity to declare static values if necessary (values that are constant across all Person instances) at the top of the module. Static methods can also be defined by attaching them to the Class object (Class really is a no more than an instance factory).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment