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

Design patterns in javascript

  • 1.
    Design patterns inJavascript Miao Siyu
  • 2.
    Why need designpatterns • Easy & nature: read, use/follow, extend/re- use, co-operator(expose api, split work…)… • Efficiency & memory cost/gc…
  • 3.
    books • 'Patterns OfEnterprise 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 DesignPattern • 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 • varanotherCar = 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 ModulePattern 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 varTodoList = 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 objectextension 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 inJQuery 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.
  • 30.