SlideShare uma empresa Scribd logo
1 de 30
Design patterns in Javascript


           Miao Siyu
Why need design patterns

• Easy & nature: read, use/follow, extend/re-
  use, co-operator(expose api, split work…)…

• Efficiency & memory cost/gc…
books
• 'Patterns Of Enterprise Application
  Architecture' Martin Fowler
• 'JavaScript Patterns' Stoyan Stefanov
• 'Pro JavaScript Design Patterns' Ross Harmes
  and Dustin Diaz
• 'Learning JavaScript Design Patterns' Addy
  Osmani
• …
Categories Of Design Pattern
• Creational Design Patterns
  Constructor, Factory, Abstract, Prototype, Singleton and Builder

• Structural Design Patterns
  Decorator, Facade, Flyweight, Adapter and Proxy

• Behavioral Design Patterns
  Iterator, Mediator, Observer and Visitor
Create an object
   • var newObject = {};
   • var newObject = Object.create(…);
   • var newObject = new Class();




http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
Define properties
• newObject.someKey = …;
• newObject*“someKey”+ = …;
• Object.defineProperty(newObject, “someKey”,,
     // property attributes here: value, writable…
  })
• function Car(model, color){
     this.model = model;
     this.color = color
  }
  Car.prototype.run = function(),console.log(“run”)-;
Prototype pattern
• var anotherCar = Object.create( someCar );
• var beget = (function () {
     function F() {};
     return function (proto) {
        F.prototype = proto;
        return new F();
     };
  })();         Clone using prototype: avoid the inherent cost
Singleton pattern
var Singleton = (function () { Anonymous Function
          var instantiated;
          function init() {
                    return {
                               publicMethod: function () {},
                               publicProperty: 'test'
                    };
          }
          return {
                    getInstance: function () {
                               if (!instantiated) {
                                           instantiated = init();
                               }
                               return instantiated;
                    }
          };
})();              Singleton.getInstance().publicMethod();
Module pattern
                                                               Loose Augumentation:

var myNamespace = (function () {                               var MODULE = (function (my) {
         var myPrivateVar = 0;                                         // add capabilities...
         var myPrivateMethod = function (someText) {                   return my;
                    console.log(someText);                     }(MODULE || {}));
         };                                              Option 1: var myApplication = myApplication || {};
                                                         Option 2 if(!MyApplication) MyApplication = {};
         return {                                        Option 3: var myApplication = myApplication = myApplication || {}
                                                         Option 4: myApplication || (myApplication = {});
                    myPublicVar: "foo",                  Option 5: var myApplication = myApplication === undefined ? {} :
                                                         myApplication;
                    myPublicFunction: function (bar) {
                                myPrivateVar++;                Cloning & Inheritance
                                myPrivateMethod(bar);
                                                               for (key in old) {
                    }
                                                                  if (old.hasOwnProperty(key)) {
         };
                                                                     my[key] = old[key];
})();                                                             }
                                                                }


         http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
The Revealing Module Pattern
var myRevealingModule = (function(){
       var name = 'John Smith';
       function setPerson (personName) {
                name = personName;
       }
       function getPerson () {
                                     Advantage: same style
                return name;
       }                             Disadvantage: when over-writting
       return {
                // set: setPerson,
                get: getPerson
       };
}());
Observer Pattern & Mediator Pattern
var pubsub = {};                           q.subscribe = function( topic, func ) {   q.unsubscribe = function( token ) {
(function(q) {                               if (!topics[topic]) {                      for ( var m in topics ) {
 var topics = {},                              topics[topic] = [];                        if ( topics[m] ) {
 subUid = -1;                                }                                              for (var i = 0, j = topics[m].length; i < j; i++) {
 q.publish = function( topic, args ) {       var token = (++subUid).toString();               if (topics[m][i].token === token) {
                                               topics[topic].push({                             topics[m].splice(i, 1);
  if ( !topics[topic] ) {                       token: token,                                   return token;
    return false;                               func: func                                    }
  }                                            });                                          }
  var subscribers = topics[topic],           return token;                                }
  var tempArr;                             };                                           }
                                                                                        return this;
  if(subscribers ) {                                                                  };
     tempArr = subscribers .slice(0);                                                }( pubsub ));
     while (tempArr .length) {
        tempArr.pop().func(topic, args);
     }
  }
                                                    Backbone.js: listen to changes in model
  return this;
 };

             Mediator Pattern: Colleague – communicate by -> Mediator
            Observer - listener to -> Mediator
Mediator:
Communication between Colleague




                     Façade: N-to-1, listener to a event hub
Command Pattern
(function(){
   var CarManager = {
      requestInfo: function( model, id ){},
      buyVehicle: function( model, id ){},
      arrangeViewing: function( model, id ){}
   };
                                                           We can keep track of the commands,
})();                                                           also record a game reply
           CarManager.execute("arrangeViewing", "Ferrari", "14523");
           CarManager.execute("requestInfo", "Ford Escort", "34232");
           CarManager.execute("buyVehicle", "Ford Escort", "34232");


CarManager.execute = function (name) {
   // we can log the commands here, also implements an undo function
   return CarManager[name] && CarManager[name].apply(CarManager, [].slice.call(arguments, 1));
};
Façade Pattern
                                            function setStyles(elements, styles) {
var foo = document.getElementById('foo');    for (var i=0, length = elements.length; i < length; i++) {
foo.style.color = 'red';                      var element = document.getElementById(elements[i]);
foo.style.width = '150px';
                                              for (var property in styles) {
var bar = document.getElementById('bar');      element.style[property] = styles[property];
                                              }
 bar.style.color = 'red';
                                             }
 bar.style.width = '150px';
                                            }

var baz = document.getElementById('baz');   //Now you can just write this:
baz.style.color = 'red';                    setStyles(['foo', 'bar', 'baz'], {
baz.style.width = '150px';                   color: 'red',
                                             width: '150px'
                                            });


             Very common in Jquery: .css(), .animate()…
Factory Pattern
var AbstractVehicleFactory = (function () {
            var types = {};
            return {
                         getVehicle: function (type, customizations) {
                                      // we can keep track of vehicle or get vehicle by options instead of type …
                                      var Vehicle = types[type];
                                      return (Vehicle) ? return new Vehicle(customizations) : null;
                         },
                         registerVehicle: function (type, Vehicle) {
                                      var proto = Vehicle.prototype;
                                      if (proto.drive && proto.breakDown) {
                                                    types[type] = Vehicle;
                                      }
                                      return AbstractVehicleFactory;
                         }
            };
})();

AbstractVehicleFactory.registerVehicle("car", Car);                        Give me a android phone with
AbstractVehicleFactory.registerVehicle("truck", Truck);                     4.1 inch screen around S$400
var car = AbstractVehicleFactory.getVehicle("car", { color: "yellow", turbo: true });
var truck = AbstractVehicleFactory.getVehicle("truck", { monster: true, cylinders: 12 });
Mixin Pattern
function augment( receivingClass, givingClass ) {        var Car = function( settings ){
  if ( arguments[2] ) {                                              this.model = settings.model ;
     for (var i=2, len=arguments.length; i<len; i++) {               this.colour = settings.colour ;
        receivingClass.prototype[arguments[i]] =         };
           givingClass.prototype[arguments[i]];
     }                                                   var Mixin = function(){};
  }
                                                         Mixin.prototype = {
  else {
                                                                    driveForward: function(){},
     for ( var methodName in givingClass.prototype ) {
        if ( !receivingClass.prototype[methodName] ) {
                                                                    driveBackward: function(){}
           receivingClass.prototype[methodName] =        };
               givingClass.prototype[methodName];
        }                                                augment( Car, Mixin,'driveForward','driveBackward' );
     }
  }                                                      var vehicle = new Car({model:'Ford', colour:'blue'});
}
                                                         vehicle.driveForward();
                                                         vehicle.driveBackward();



   We have update our factory to produce                       Class level
         tanks with new weapon
Decorator Pattern
• SubClassing
 var Person = function( firstName , lastName ){                         Object level
           this.firstName = firstName;
           this.lastName = lastName;
           this.gender = 'male'
 };

 var Superhero = function( firstName, lastName , powers ){
           Person.call(this, firstName, lastName);
           this.powers = powers;
 }
 SuperHero.prototype = Object.create(Person.prototype);

 var superman = new Superhero( "Clark" ,"Kent" , ['flight','heat-vision'] );
• Simple decorator                               • Mulit decorator
function Vehicle( vehicleType ){
                                             function MacBook() {
  this.vehicleType = vehicleType || 'car',     this.cost = function () { return 997; };
  this.model = 'default',                      this.screenSize = function () { return 13.3; };
  this.license = '00000-000'                 }
}                                            function Memory( macbook ) {
function makeTruck(truck){                     var v = macbook.cost();
  truck.setModel =function( modelName ){}      macbook.cost = function() { return v + 75 ;}
                                             }
  truck.setColor = function( color ){}       function LargeScreen( macbook ){
  return truck;                                var v = macbook.cost();
}                                              macbook.cost = function(){ return v + 100; };
                                               macbook.screenSize=function(){ return 14.8; };
var truck = makeTruck(new Vehicle());        }
                                             function Insurance( macbook ){
                                             var v = macbook.cost();
                                               macbook.cost = function(){ return v + 250; };
                                             }

                                             var mb = new MacBook();
                                             Memory(mb);
                                             LargeScreen(mb);
                                             Insurance(mb);
   user can wear equips to change attr
          and gain new ablitities
Pseudo-classical decorators: interface
var TodoList = new Interface('Composite', ['add', 'remove']);
var TodoItem = new Interface('TodoItem', ['save']);

var myTodoList = function(id, method, action) {
   // implements TodoList, TodoItem
};
                                                         Make sure that only archers
function addTodo( todoInstance ) {                         can enter certain stage
  Interface.ensureImplements(todoInstance, TodoList, TodoItem);
  // …
}

https://gist.github.com/1057989
var Interface = function(name, methods),…-
Interface.ensureImplements = function(obj),…-
Flyweight pattern
var Book = function(){                      Book info:
   this.id = id;                            var Book = function () {
   this.title = title;                         this.title = title;
   this.author = author;                       this.author = author;
   this.genre = genre;                         this.genre = genre;
   this.pageCount = pageCount;                 this.pageCount = pageCount;
   this.publisherID = publisherID;             this.publisherID = publisherID;
   this.ISBN = ISBN;                           this.ISBN = ISBN;
   this.checkoutDate = checkoutDate;        };
   this.checkoutMember = checkoutMember;
   this.dueReturnDate = dueReturnDate;
   this.availability = availability;                   Checkout Info:
};


                      Share date as much as possible
var BookRecordManager = (function () {
var BookFactory = (function () {                     var bookRecordDatabase = {};
    var existingBooks = {};                          return {
    return {
      createBook: function () {                               addBookRecord: function (
         var existingBook = existingBooks[ISBN];                 var book = bookFactory.createBook();
         if (existingBook) {                                     bookRecordDatabase[id] = {
            return existingBook;                                    checkoutMember: checkoutMember,
         } else {                                                   checkoutDate: checkoutDate,
            var book = new Book();                                  dueReturnDate: dueReturnDate,
            existingBooks[ISBN] = book;                             availability: availability,
            return book;                                            book: book
         }                                                       };
      }                                                       },
    }
});                                                           updateCheckoutStatus: function () {},
                                                              extendCheckoutPeriod: function () {},
                                                              isPastDue: function (bookID) {}
                                                         };
                                                   });
Object Pool
Pool = {arr:[]};

Pool.pop = function(){
  if(Pool.arr.length > 0){
     return Pool.arr.pop().wake();
  }else{
     return new Obj();
  }
}                                                 May have hundreds of planes through the
Pool.push= function(obj){                         whole game, but not more than 20 at
                                                  the same time.
  Pool.arr.push(obj);
  obj.sleep();                                    Generator a plan: pop()
}                                                 Leave screen or destroyed: push()
Object pools are used to avoid the instantiation
cost of creating new objects by re-using existing
ones. Avoid creating objects is gc-friendly.      Reuse resource when it has a high cost to
                                                  make or release, eg. connection pool
MV* pattern
• V: Templing
        Handlebars, Underscore…
• *: bind event, route, render, data-binding…
• C: flex, extendable, suit for big project
        Backbone, Spine…
• P: Present Model -> View, view no direct access to model,
  safer then MVC
        Backbone , Angular…
• VM: VM & V more tightly, suit small project
        Knockout…


TODO MVC http://todomvc.com/
Namespace
     • Automating nested namespacing
                        // automatic namespacing
                        var myApp = myApp || {};
var application = {
 utilities:{            function extend( ns, ns_string ) {
   drawing:{              var parts = ns_string.split('.'),
     canvas:{             parent = ns,
       2d:{}              pl, i;
     }                    pl = parts.length;
   }                      for (i = 0; i < pl; i++) {
 }                          if (typeof parent[parts[i]] == 'undefined') {
};                            parent[parts[i]] = {};
                            }
                            parent = parent[parts[i]];
                          }
                          return parent;
                        }

                        var mod = extend(myApp, 'myApp.modules.module2');
• Deep object extension
function extend(destination, source) {
 var toString = Object.prototype.toString,
 objTest = toString.call({});
 for (var property in source) {
   if (source[property] && objTest == toString.call(source[property])) {
     destination[property] = destination[property] || {};
     extend(destination[property], source[property]);
   } else {
     destination[property] = source[property];
   }
 }
 return destination;
};


  Jquery.extend
Design pattern in JQuery core
• Adapter pattern
       .css({opacity:.5})
• Façade pattern
       .ajax()
• Observe pattern
       .on(event, cssSelector, func)
• Iterator pattern
       array is also object
• Proxy pattern
       .proxy(function(),this…-, thisObj) control before sth really
loaded
• Builder Pattern
       $(“<a>a link</a>”).appendTo(…) xml initing
Modular JS
• AMD
• CMD        Script loaders
• Harmony
AMD
•   Asynchronous Module Definition, Commonjs
•   RequireJS
•   define(moduleID, [dependencies], definition function)
•   require([dependencies], function)

     https://github.com/amdjs/amdjs-api/wiki/AMD
CMD
 • require()
 • Exports                               http://wiki.commonjs.org/wiki/Modules/Wrappings

cmd: Common Module Definition

Sea.js   define(function(require, exports, module) { // The module code goes here });



• Modules are singletons.
• New free variables within the module scope should not be introduced.
• Execution must be lazy, import can be later: define(dependency, …) vs.
  define(function(require(…))
• With some care, modules may have cyclic dependencies.
harmony
• Export
• Import
• Module

Mais conteúdo relacionado

Mais procurados

Part 3-functions
Part 3-functionsPart 3-functions
Part 3-functions
ankita44
 
User defined functions
User defined functionsUser defined functions
User defined functions
shubham_jangid
 

Mais procurados (20)

Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
Say It With Javascript
Say It With JavascriptSay It With Javascript
Say It With Javascript
 
Part 3-functions
Part 3-functionsPart 3-functions
Part 3-functions
 
Scala in practice
Scala in practiceScala in practice
Scala in practice
 
Functions123
Functions123 Functions123
Functions123
 
Functions12
Functions12Functions12
Functions12
 
Grammarware Memes
Grammarware MemesGrammarware Memes
Grammarware Memes
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 
User defined functions
User defined functionsUser defined functions
User defined functions
 
Zope component architechture
Zope component architechtureZope component architechture
Zope component architechture
 
Empathic Programming - How to write comprehensible code
Empathic Programming - How to write comprehensible codeEmpathic Programming - How to write comprehensible code
Empathic Programming - How to write comprehensible code
 
The Macronomicon
The MacronomiconThe Macronomicon
The Macronomicon
 
Introduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in HaskellIntroduction to ad-3.4, an automatic differentiation library in Haskell
Introduction to ad-3.4, an automatic differentiation library in Haskell
 
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDBTDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
TDC2016POA | Trilha .NET - CQRS e ES na prática com RavenDB
 
Imugi: Compiler made with Python
Imugi: Compiler made with PythonImugi: Compiler made with Python
Imugi: Compiler made with Python
 
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
 
The Ring programming language version 1.7 book - Part 35 of 196
The Ring programming language version 1.7 book - Part 35 of 196The Ring programming language version 1.7 book - Part 35 of 196
The Ring programming language version 1.7 book - Part 35 of 196
 
Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)Being functional in PHP (DPC 2016)
Being functional in PHP (DPC 2016)
 
Object Oriented JavaScript
Object Oriented JavaScriptObject Oriented JavaScript
Object Oriented JavaScript
 

Semelhante a Design patterns in javascript

HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
Dmitry Soshnikov
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
Adam Crabtree
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
偉格 高
 
Get started with YUI
Get started with YUIGet started with YUI
Get started with YUI
Adam Lu
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
Jarod Ferguson
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
Fabien Potencier
 

Semelhante a Design patterns in javascript (20)

25-functions.ppt
25-functions.ppt25-functions.ppt
25-functions.ppt
 
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
HelsinkiJS meet-up. Dmitry Soshnikov - ECMAScript 6
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Advanced JavaScript
Advanced JavaScriptAdvanced JavaScript
Advanced JavaScript
 
Type script, for dummies
Type script, for dummiesType script, for dummies
Type script, for dummies
 
LinkedIn TBC JavaScript 100: Functions
 LinkedIn TBC JavaScript 100: Functions LinkedIn TBC JavaScript 100: Functions
LinkedIn TBC JavaScript 100: Functions
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Engineering JavaScript
Engineering JavaScriptEngineering JavaScript
Engineering JavaScript
 
JavaScript - i och utanför webbläsaren (2010-03-03)
JavaScript - i och utanför webbläsaren (2010-03-03)JavaScript - i och utanför webbläsaren (2010-03-03)
JavaScript - i och utanför webbläsaren (2010-03-03)
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
V8
V8V8
V8
 
Javascript Design Patterns
Javascript Design PatternsJavascript Design Patterns
Javascript Design Patterns
 
Get started with YUI
Get started with YUIGet started with YUI
Get started with YUI
 
Build Widgets
Build WidgetsBuild Widgets
Build Widgets
 
Taming that client side mess with Backbone.js
Taming that client side mess with Backbone.jsTaming that client side mess with Backbone.js
Taming that client side mess with Backbone.js
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)Be RESTful (Symfony Camp 2008)
Be RESTful (Symfony Camp 2008)
 
CoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love AffairCoffeeScript - A Rubyist's Love Affair
CoffeeScript - A Rubyist's Love Affair
 

Design patterns in javascript

  • 1. Design patterns in Javascript Miao Siyu
  • 2. Why need design patterns • Easy & nature: read, use/follow, extend/re- use, co-operator(expose api, split work…)… • Efficiency & memory cost/gc…
  • 3. books • 'Patterns Of Enterprise Application Architecture' Martin Fowler • 'JavaScript Patterns' Stoyan Stefanov • 'Pro JavaScript Design Patterns' Ross Harmes and Dustin Diaz • 'Learning JavaScript Design Patterns' Addy Osmani • …
  • 4. Categories Of Design Pattern • Creational Design Patterns Constructor, Factory, Abstract, Prototype, Singleton and Builder • Structural Design Patterns Decorator, Facade, Flyweight, Adapter and Proxy • Behavioral Design Patterns Iterator, Mediator, Observer and Visitor
  • 5. Create an object • var newObject = {}; • var newObject = Object.create(…); • var newObject = new Class(); http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
  • 6. Define properties • newObject.someKey = …; • newObject*“someKey”+ = …; • Object.defineProperty(newObject, “someKey”,, // property attributes here: value, writable… }) • function Car(model, color){ this.model = model; this.color = color } Car.prototype.run = function(),console.log(“run”)-;
  • 7. Prototype pattern • var anotherCar = Object.create( someCar ); • var beget = (function () { function F() {}; return function (proto) { F.prototype = proto; return new F(); }; })(); Clone using prototype: avoid the inherent cost
  • 8. Singleton pattern var Singleton = (function () { Anonymous Function var instantiated; function init() { return { publicMethod: function () {}, publicProperty: 'test' }; } return { getInstance: function () { if (!instantiated) { instantiated = init(); } return instantiated; } }; })(); Singleton.getInstance().publicMethod();
  • 9. Module pattern Loose Augumentation: var myNamespace = (function () { var MODULE = (function (my) { var myPrivateVar = 0; // add capabilities... var myPrivateMethod = function (someText) { return my; console.log(someText); }(MODULE || {})); }; Option 1: var myApplication = myApplication || {}; Option 2 if(!MyApplication) MyApplication = {}; return { Option 3: var myApplication = myApplication = myApplication || {} Option 4: myApplication || (myApplication = {}); myPublicVar: "foo", Option 5: var myApplication = myApplication === undefined ? {} : myApplication; myPublicFunction: function (bar) { myPrivateVar++; Cloning & Inheritance myPrivateMethod(bar); for (key in old) { } if (old.hasOwnProperty(key)) { }; my[key] = old[key]; })(); } } http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
  • 10. The Revealing Module Pattern var myRevealingModule = (function(){ var name = 'John Smith'; function setPerson (personName) { name = personName; } function getPerson () { Advantage: same style return name; } Disadvantage: when over-writting return { // set: setPerson, get: getPerson }; }());
  • 11. Observer Pattern & Mediator Pattern var pubsub = {}; q.subscribe = function( topic, func ) { q.unsubscribe = function( token ) { (function(q) { if (!topics[topic]) { for ( var m in topics ) { var topics = {}, topics[topic] = []; if ( topics[m] ) { subUid = -1; } for (var i = 0, j = topics[m].length; i < j; i++) { q.publish = function( topic, args ) { var token = (++subUid).toString(); if (topics[m][i].token === token) { topics[topic].push({ topics[m].splice(i, 1); if ( !topics[topic] ) { token: token, return token; return false; func: func } } }); } var subscribers = topics[topic], return token; } var tempArr; }; } return this; if(subscribers ) { }; tempArr = subscribers .slice(0); }( pubsub )); while (tempArr .length) { tempArr.pop().func(topic, args); } } Backbone.js: listen to changes in model return this; }; Mediator Pattern: Colleague – communicate by -> Mediator Observer - listener to -> Mediator
  • 12. Mediator: Communication between Colleague Façade: N-to-1, listener to a event hub
  • 13. Command Pattern (function(){ var CarManager = { requestInfo: function( model, id ){}, buyVehicle: function( model, id ){}, arrangeViewing: function( model, id ){} }; We can keep track of the commands, })(); also record a game reply CarManager.execute("arrangeViewing", "Ferrari", "14523"); CarManager.execute("requestInfo", "Ford Escort", "34232"); CarManager.execute("buyVehicle", "Ford Escort", "34232"); CarManager.execute = function (name) { // we can log the commands here, also implements an undo function return CarManager[name] && CarManager[name].apply(CarManager, [].slice.call(arguments, 1)); };
  • 14. Façade Pattern function setStyles(elements, styles) { var foo = document.getElementById('foo'); for (var i=0, length = elements.length; i < length; i++) { foo.style.color = 'red'; var element = document.getElementById(elements[i]); foo.style.width = '150px'; for (var property in styles) { var bar = document.getElementById('bar'); element.style[property] = styles[property]; } bar.style.color = 'red'; } bar.style.width = '150px'; } var baz = document.getElementById('baz'); //Now you can just write this: baz.style.color = 'red'; setStyles(['foo', 'bar', 'baz'], { baz.style.width = '150px'; color: 'red', width: '150px' }); Very common in Jquery: .css(), .animate()…
  • 15. Factory Pattern var AbstractVehicleFactory = (function () { var types = {}; return { getVehicle: function (type, customizations) { // we can keep track of vehicle or get vehicle by options instead of type … var Vehicle = types[type]; return (Vehicle) ? return new Vehicle(customizations) : null; }, registerVehicle: function (type, Vehicle) { var proto = Vehicle.prototype; if (proto.drive && proto.breakDown) { types[type] = Vehicle; } return AbstractVehicleFactory; } }; })(); AbstractVehicleFactory.registerVehicle("car", Car); Give me a android phone with AbstractVehicleFactory.registerVehicle("truck", Truck); 4.1 inch screen around S$400 var car = AbstractVehicleFactory.getVehicle("car", { color: "yellow", turbo: true }); var truck = AbstractVehicleFactory.getVehicle("truck", { monster: true, cylinders: 12 });
  • 16. Mixin Pattern function augment( receivingClass, givingClass ) { var Car = function( settings ){ if ( arguments[2] ) { this.model = settings.model ; for (var i=2, len=arguments.length; i<len; i++) { this.colour = settings.colour ; receivingClass.prototype[arguments[i]] = }; givingClass.prototype[arguments[i]]; } var Mixin = function(){}; } Mixin.prototype = { else { driveForward: function(){}, for ( var methodName in givingClass.prototype ) { if ( !receivingClass.prototype[methodName] ) { driveBackward: function(){} receivingClass.prototype[methodName] = }; givingClass.prototype[methodName]; } augment( Car, Mixin,'driveForward','driveBackward' ); } } var vehicle = new Car({model:'Ford', colour:'blue'}); } vehicle.driveForward(); vehicle.driveBackward(); We have update our factory to produce Class level tanks with new weapon
  • 17. Decorator Pattern • SubClassing var Person = function( firstName , lastName ){ Object level this.firstName = firstName; this.lastName = lastName; this.gender = 'male' }; var Superhero = function( firstName, lastName , powers ){ Person.call(this, firstName, lastName); this.powers = powers; } SuperHero.prototype = Object.create(Person.prototype); var superman = new Superhero( "Clark" ,"Kent" , ['flight','heat-vision'] );
  • 18. • Simple decorator • Mulit decorator function Vehicle( vehicleType ){ function MacBook() { this.vehicleType = vehicleType || 'car', this.cost = function () { return 997; }; this.model = 'default', this.screenSize = function () { return 13.3; }; this.license = '00000-000' } } function Memory( macbook ) { function makeTruck(truck){ var v = macbook.cost(); truck.setModel =function( modelName ){} macbook.cost = function() { return v + 75 ;} } truck.setColor = function( color ){} function LargeScreen( macbook ){ return truck; var v = macbook.cost(); } macbook.cost = function(){ return v + 100; }; macbook.screenSize=function(){ return 14.8; }; var truck = makeTruck(new Vehicle()); } function Insurance( macbook ){ var v = macbook.cost(); macbook.cost = function(){ return v + 250; }; } var mb = new MacBook(); Memory(mb); LargeScreen(mb); Insurance(mb); user can wear equips to change attr and gain new ablitities
  • 19. Pseudo-classical decorators: interface var TodoList = new Interface('Composite', ['add', 'remove']); var TodoItem = new Interface('TodoItem', ['save']); var myTodoList = function(id, method, action) { // implements TodoList, TodoItem }; Make sure that only archers function addTodo( todoInstance ) { can enter certain stage Interface.ensureImplements(todoInstance, TodoList, TodoItem); // … } https://gist.github.com/1057989 var Interface = function(name, methods),…- Interface.ensureImplements = function(obj),…-
  • 20. Flyweight pattern var Book = function(){ Book info: this.id = id; var Book = function () { this.title = title; this.title = title; this.author = author; this.author = author; this.genre = genre; this.genre = genre; this.pageCount = pageCount; this.pageCount = pageCount; this.publisherID = publisherID; this.publisherID = publisherID; this.ISBN = ISBN; this.ISBN = ISBN; this.checkoutDate = checkoutDate; }; this.checkoutMember = checkoutMember; this.dueReturnDate = dueReturnDate; this.availability = availability; Checkout Info: }; Share date as much as possible
  • 21. var BookRecordManager = (function () { var BookFactory = (function () { var bookRecordDatabase = {}; var existingBooks = {}; return { return { createBook: function () { addBookRecord: function ( var existingBook = existingBooks[ISBN]; var book = bookFactory.createBook(); if (existingBook) { bookRecordDatabase[id] = { return existingBook; checkoutMember: checkoutMember, } else { checkoutDate: checkoutDate, var book = new Book(); dueReturnDate: dueReturnDate, existingBooks[ISBN] = book; availability: availability, return book; book: book } }; } }, } }); updateCheckoutStatus: function () {}, extendCheckoutPeriod: function () {}, isPastDue: function (bookID) {} }; });
  • 22. Object Pool Pool = {arr:[]}; Pool.pop = function(){ if(Pool.arr.length > 0){ return Pool.arr.pop().wake(); }else{ return new Obj(); } } May have hundreds of planes through the Pool.push= function(obj){ whole game, but not more than 20 at the same time. Pool.arr.push(obj); obj.sleep(); Generator a plan: pop() } Leave screen or destroyed: push() Object pools are used to avoid the instantiation cost of creating new objects by re-using existing ones. Avoid creating objects is gc-friendly. Reuse resource when it has a high cost to make or release, eg. connection pool
  • 23. MV* pattern • V: Templing Handlebars, Underscore… • *: bind event, route, render, data-binding… • C: flex, extendable, suit for big project Backbone, Spine… • P: Present Model -> View, view no direct access to model, safer then MVC Backbone , Angular… • VM: VM & V more tightly, suit small project Knockout… TODO MVC http://todomvc.com/
  • 24. Namespace • Automating nested namespacing // automatic namespacing var myApp = myApp || {}; var application = { utilities:{ function extend( ns, ns_string ) { drawing:{ var parts = ns_string.split('.'), canvas:{ parent = ns, 2d:{} pl, i; } pl = parts.length; } for (i = 0; i < pl; i++) { } if (typeof parent[parts[i]] == 'undefined') { }; parent[parts[i]] = {}; } parent = parent[parts[i]]; } return parent; } var mod = extend(myApp, 'myApp.modules.module2');
  • 25. • Deep object extension function extend(destination, source) { var toString = Object.prototype.toString, objTest = toString.call({}); for (var property in source) { if (source[property] && objTest == toString.call(source[property])) { destination[property] = destination[property] || {}; extend(destination[property], source[property]); } else { destination[property] = source[property]; } } return destination; }; Jquery.extend
  • 26. Design pattern in JQuery core • Adapter pattern .css({opacity:.5}) • Façade pattern .ajax() • Observe pattern .on(event, cssSelector, func) • Iterator pattern array is also object • Proxy pattern .proxy(function(),this…-, thisObj) control before sth really loaded • Builder Pattern $(“<a>a link</a>”).appendTo(…) xml initing
  • 27. Modular JS • AMD • CMD Script loaders • Harmony
  • 28. AMD • Asynchronous Module Definition, Commonjs • RequireJS • define(moduleID, [dependencies], definition function) • require([dependencies], function) https://github.com/amdjs/amdjs-api/wiki/AMD
  • 29. CMD • require() • Exports http://wiki.commonjs.org/wiki/Modules/Wrappings cmd: Common Module Definition Sea.js define(function(require, exports, module) { // The module code goes here }); • Modules are singletons. • New free variables within the module scope should not be introduced. • Execution must be lazy, import can be later: define(dependency, …) vs. define(function(require(…)) • With some care, modules may have cyclic dependencies.