Created
April 23, 2012 21:38
-
Star
(112)
You must be signed in to star a gist -
Fork
(12)
You must be signed in to fork a gist
Revisions
-
jonnyreeves revised this gist
May 14, 2012 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -79,6 +79,7 @@ define(function () { * example, if we introduced a BankManager class which extended our Person class, we could write: * * `BankManager.prototype = Person.prototype` * `BankManager.prototype.constructor = BankManager` * * However, due to the dynamic nature of JavaScript I am of the opinion that favouring composition * over inheritance will make your code easier to read and re-use. -
jonnyreeves revised this gist
May 14, 2012 . 1 changed file with 8 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -84,6 +84,14 @@ define(function () { * over inheritance will make your code easier to read and re-use. */ Person.prototype = { /** * Whenever you replace an Object's Prototype, you need to repoint * the base Constructor back at the original constructor Function, * otherwise `instanceof` calls will fail. */ constructor: Person, /** * All methods added to a Class' prototype are public (visible); they are able to * access the properties and methods of the Person class via the `this` keyword. Note that -
jonnyreeves revised this gist
Apr 24, 2012 . 1 changed file with 4 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,9 @@ /** * Here's a simple usecase for our Person class, again we will start by using requireJS to 'define' a * new class; however note how we pass the `require` object through to the closure as an argument, this * allows us to retrieve other exported modules / class definitions that have been 'define'd. */ define(function (require) { "use strict"; // requireJS will ensure that the Person definition is available to use, we can now import -
jonnyreeves revised this gist
Apr 23, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,7 +15,7 @@ define(function () { * This is our classes constructor; unlike AS3 this is where we define our member properties (fields). * To differentiate constructor functions from regular functions, by convention we start the function * name with a capital letter. This informs users that they must invoke the Person function using * the `new` keyword and treat it as a constructor (ie: it returns a new instance of the Class). */ function Person(name) { // This first guard ensures that the callee has invoked our Class' constructor function -
jonnyreeves revised this gist
Apr 23, 2012 . 1 changed file with 3 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -63,8 +63,7 @@ define(function () { * and are static as a result. */ function formatNameAndAge(person) { // Note that `this` does not refer to the Person object from inside this method. if (person._age === -1) { return "We don't know how old " + person.name + " is!"; } @@ -74,7 +73,7 @@ define(function () { }; /** * The prototype is a special type of Object which is used as a the blueprint for all instances * of a given Class; by defining functions and properties on the prototype we reduce memory * overhead. We can also achieve inheritance by pointing one classes' prototype at another, for * example, if we introduced a BankManager class which extended our Person class, we could write: @@ -118,7 +117,7 @@ define(function () { /** * This method access both a member property and a static property. */ canRetire: function() { return this._age >= Person.RETIREMENT_AGE; }, -
jonnyreeves created this gist
Apr 23, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ <!DOCTYPE html> <html> <head> <script data-main="usage" src="http://requirejs.org/docs/release/1.0.8/comments/require.js"></script> </head> <body> <p>Check your JavaScript console for output!</p> </body> </head> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,138 @@ /** * This example make use of requireJS to provide a clean and simple way to split JavaScript class definitions * into separate files and avoid global namespace pollution. http://requirejs.org/ * * We start by defining the definition within the require block inside a function; this means that any * new variables / methods will not be added to the global namespace; requireJS simply requires us to return * a single value (function / Object) which represents this definition. In our case, we will be returning * the Class' function. */ define(function () { // Forces the JavaScript engine into strict mode: http://tinyurl.com/2dondlh "use strict"; /** * This is our classes constructor; unlike AS3 this is where we define our member properties (fields). * To differentiate constructor functions from regular functions, by convention we start the function * name with a capital letter. This informs users that they must invoke the Person function using * the `new` keyword and treat. */ function Person(name) { // This first guard ensures that the callee has invoked our Class' constructor function // with the `new` keyword - failure to do this will result in the `this` keyword referring // to the callee's scope (typically the window global) which will result in the following fields // (name and _age) leaking into the global namespace and not being set on this object. if (!(this instanceof Person)) { throw new TypeError("Person constructor cannot be called as a function."); } // Here we create a member property (field) for the Person's name; setting its value // what the one supplied to the Constructor. Although we don't have to define // properties ahead of time (they can easily be added at runtime as all Object / functions // in JavaScript are dynamic) I believe it makes your code easier to follow if you list your // classes intentions up front (eg: in the Constructor function). this.name = name; // Here we are defining a private member. As there is no `private` keyword in JavaScript // there is no way for us to hide this data (without resorting to inelegant hacks); instead // we choose to use a naming convention where a leading underscore indicates a property // is private and should not be relied upon as part of the Classes public API. this._age = -1; } /** * Adding static properties is as simple as adding them directly to the constructor * function directly. */ Person.RETIREMENT_AGE = 60; /** * Public Static methods are defined in the same way; here's a static constructor for our Person class * which also sets the person's age. */ Person.create = function (name, age) { var result = new Person(name); result.setAge(age); return result; }; /** * Any functions not added to the Person reference won't be visible, or accessible outside of * this file (closure); however, these methods and functions don't belong to the Person class either * and are static as a result. */ function formatNameAndAge(person) { // Note that we are unable to access any member properties, or methods added to the prototype // of the Person object from inside this method. if (person._age === -1) { return "We don't know how old " + person.name + " is!"; } return (person.name + ", is " + person._age + " years old and " + ((person.canRetire()) ? "can" : "can't") + " retire"); }; /** * The prototype is a special type of Object which is used as a the Blueprint for all instances * of a given Class; by defining functions and properties on the prototype we reduce memory * overhead. We can also achieve inheritance by pointing one classes' prototype at another, for * example, if we introduced a BankManager class which extended our Person class, we could write: * * `BankManager.prototype = Person.prototype` * * However, due to the dynamic nature of JavaScript I am of the opinion that favouring composition * over inheritance will make your code easier to read and re-use. */ Person.prototype = { /** * All methods added to a Class' prototype are public (visible); they are able to * access the properties and methods of the Person class via the `this` keyword. Note that * unlike ActionScript, usage of the `this` keyword is required, failure to use it will * result in the JavaScript engine trying to resolve the definition on the global object. */ greet: function () { // Note we have to use the `this` keyword. return "Hello, " + this.name; }, /** * Even tho the `_age` property is accessible; it still makes a lot of sense to provide * mutator methods (getters / setters) which make up the public API of a Class - here we * validate the supplied value; something you can't do when a field is modified directly */ setAge: function (value) { // Ensure the supplied value is numeric. if (typeof (value) !== 'number') { throw new TypeError(typeof (value) + " is not a number."); } // Ensure the supplied value is valid. if (isNaN(value) || value < 0) { throw new RangeError("Supplied value is out of range."); } this._age = value; }, /** * This method access both a member property and a static property. */ canRetire: function() { return this._age >= Person.RETIREMENT_AGE; }, /** * Finally we can also access 'static' functions and properties. */ toString: function() { // Note that as `formatNameAndAge` is static we must supply a reference // to `this` so it can operate on this instance. return formatNameAndAge(this); } }; // As mentioned up top, requireJS needs us to return a value - in this files case, we will return // a reference to the constructor function. return Person; }); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,22 @@ /** * Here's a simple usecase for our Person class, again we will use requireJS to 'define' a new class, but * this time we will list 'Person' in the Array of required dependencies. */ define(['Person'], function () { "use strict"; // requireJS will ensure that the Person definition is available to use, we can now import // it for use (think of this as your import statement in AS3). var Person = require('Person'); // We can now invoke the constructor function to create a new instance and invoke that instance's // methods. var jonny = new Person("Jonny"); jonny.setAge(29); console.log(jonny.toString()); // We can also access any public static methods and properties attached to the Person function: var sean = Person.create("Sean", 30); console.log(sean.greet()); console.log("Generally speaking, you can retire at " + Person.RETIREMENT_AGE); });