java scriptpatterns
DESCRIPTION
Un design pattern è soluzione generale e riusabile ad un problema ricorrente; ma tutti i design patterns "classici" possono essere utilizzati in Javascript? Esistono design patterns tipici di Javascript? In questo talk vedremo quali design pattern classici si possono implementare in Javascript, e come, così come nuovi pattern possono sfruttare al massimo le caratteristiche del linguaggio.TRANSCRIPT
Giordano Scalzo
JavaScript Patterns
Wednesday, November 10, 2010
I’m not a guru!
Wednesday, November 10, 2010
I’m still learning
Wednesday, November 10, 2010
Why?
Wednesday, November 10, 2010
JavaScript isn’t this anymore
Wednesday, November 10, 2010
JavaScript is everywhere!
Wednesday, November 10, 2010
Technology Radar
JavaScript is trendy!
Wednesday, November 10, 2010
Technology Radar
JavaScript is trendy!
Wednesday, November 10, 2010
At the beginning...
Wednesday, November 10, 2010
Hacked by Brendan Eich in one week...
Wednesday, November 10, 2010
Former Mocha, renamed to JavaScript by Netscape
Wednesday, November 10, 2010
after a while...
Wednesday, November 10, 2010
and...
Wednesday, November 10, 2010
:-(
Wednesday, November 10, 2010
and so...
Wednesday, November 10, 2010
Back to study!
Wednesday, November 10, 2010
Started a notebook...
Wednesday, November 10, 2010
Essential
Scope
Wednesday, November 10, 2010
function sum(x, y){ // implied global result = x + y; return result;}
{antipattern}Wednesday, November 10, 2010
Global variables are evil!
Wednesday, November 10, 2010
Variables clash
Wednesday, November 10, 2010
Always declare variables with var
function sum(x, y){ var result = x + y; return result;}
{pattern}Wednesday, November 10, 2010
function foo(){ var a = b = 0; //...}
{antipattern}Wednesday, November 10, 2010
function foo(){ var a = (b = 0); //...}
{antipattern}
b become global
Wednesday, November 10, 2010
function foo(){ var a, b; a = b = 0; //...}
don’t use assign chain in definition
{pattern}Wednesday, November 10, 2010
function func(){ var a = 1,
b = 2, sum = a + b, myobject = {}, i, j;
// function body...}
{pattern}
Single var pattern
Wednesday, November 10, 2010
Don’t forget comma otherwise...
Wednesday, November 10, 2010
... variables become globals
Wednesday, November 10, 2010
Hoisting
myname = "global"; // global variable function func(){ // code... console.log(myname); // "undefined"
// code... var myname = "local"; console.log(myname); // "local"}
func();
{antipattern}Wednesday, November 10, 2010
Hoisting
myname = "global"; // global variable function func(){ var myname = "declared"; // code... console.log(myname); // "declared"
// code... myname = "local"; console.log(myname); // "local"}
func();
{pattern}Wednesday, November 10, 2010
“Variables should be declared as close to their usage as possible”
Robert C. Martin - Clean Code
Against minimum vertical distance principle
Wednesday, November 10, 2010
EssentialLiteral and Constructor
Wednesday, November 10, 2010
In JavaScript almost everything is an object
Wednesday, November 10, 2010
var person = new Object();person.name = "Scott";person.say = function(){ return "I am " + this.name;};
console.log(person.say());
It’s easy...
Wednesday, November 10, 2010
var person = new Object();person.name = "Scott";person.say = function(){ return "I am " + this.name;};
console.log(person.say());
{antipattern}
but wrong! :-(
Wednesday, November 10, 2010
var person = {};person.name = "Scott";person.say = function(){ return "I am " + this.name;};
console.log(person.say());
{pattern}Wednesday, November 10, 2010
What if we need similar objects...
var person = {};person.name = "Scott";person.say = function(){ return "I am " + this.name;};console.log(person.say()); // I am Scott
var otherPerson = {};otherPerson.name = "Tiger";otherPerson.say = function(){ return "I am " + this.name;};
console.log(otherPerson.say()); // I am Tiger
Wednesday, November 10, 2010
A lot of duplication
var person = {};person.name = "Scott";person.say = function(){ return "I am " + this.name;};console.log(person.say()); // I am Scott
var otherPerson = {};otherPerson.name = "Tiger";otherPerson.say = function(){ return "I am " + this.name;};
console.log(otherPerson.say()); // I am Tiger
Wednesday, November 10, 2010
Duplication is evil!
Wednesday, November 10, 2010
var Person = function(name){ this.name = name; this.say = function(){ return "I am " + this.name; }}var person = new Person("Scott");
console.log(person.say()); // I am Scott
Custom Constructor Functions
{pattern}Wednesday, November 10, 2010
Behind the scenes...
var Person = function(name){ // var this = {}; this.name = name; this.say = function(){ return "I am " + this.name; }; // return this;};
{pattern}Wednesday, November 10, 2010
var Person = function(name){ this.name = name; this.say = function(){ return "I am " + this.name; };};
var scott = new Person('Scott');var tiger = new Person('Tiger');
console.log(scott.say());console.log(tiger.say());
So, at the end...
{pattern}Wednesday, November 10, 2010
What if we forget new?
Wednesday, November 10, 2010
var Person = function(name){ this.name = name; this.say = function(){ return "I am " + this.name; };};
var scott = new Person('Scott')var adam = Person('Adam')
console.log(typeof scott); //objectconsole.log(scott.name); // Scottconsole.log(typeof adam); //'undefined'console.log(window.name); // Adam
this will point to global object
Wednesday, November 10, 2010
Enforce new pattern one: naming convention
Wednesday, November 10, 2010
var Person = function(name){ var that = {}; that.name = name; that.say = function(){ return "I am " + that.name;}; return that;};
var scott = new Person('Scott')var adam = Person('Adam')
console.log(typeof scott); //Objectconsole.log(scott.name); // Scott
console.log(typeof adam); //Objectconsole.log(adam.name); // Adam
{pattern}Wednesday, November 10, 2010
Drawback: we loose prototype reference :-(
var Person = function(name){ var that = {}; that.name = name; that.say = function(){ return "I am " + that.name; }; return that;};
Person.prototype.iamhumanbeing = true;
var scott = new Person('Scott')var adam = Person('Adam')
console.log(scott.iamhumanbeing); // undefinedconsole.log(adam.iamhumanbeing); // undefined
Wednesday, November 10, 2010
Interm!zoPrototype property
Wednesday, November 10, 2010
Define ancestors chain
var foo = {one: 1, two: 2};var bar = {three: 3};foo.__proto__ = bar;console.log(foo.one);console.log(foo.three);
Wednesday, November 10, 2010
foo
one: 1
__proto__
bar
three: 3
two: 2
Wednesday, November 10, 2010
var Person = function(name){ // this.prototype = {constructor: this} var that = {}; that.name = name; that.say = function(){ return "I am " + that.name; }; return that;};
Behind the scenes...
Wednesday, November 10, 2010
var Person = function(name){ if (this instanceof Person) { this.name = name; this.say = function(){ return "I am " + that.name; } } else { return new Person(name); }};Person.prototype.iamhumanbeing = true;var scott = new Person('Scott')var adam = Person('Adam')console.log(scott.name); // Scottconsole.log(adam.name); // Adamconsole.log(scott.iamhumanbeing); // trueconsole.log(adam.iamhumanbeing); // true
Self invoking constructor
{pattern}Wednesday, November 10, 2010
EssentialFunctions
Wednesday, November 10, 2010
Functions as first class objects
Wednesday, November 10, 2010
Immediate functions
(function(){ alert('watch out!');})();
Wednesday, November 10, 2010
Initialization pattern
(function(){ var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], today = new Date(), msg = 'Today is ' + days[today.getDay()] + ', ' + today.getDate(); console.log(msg);})(); // "Today is Wed, 10"
{pattern}Wednesday, November 10, 2010
Function scope
Wednesday, November 10, 2010
// constructors function Parent(){}
function Child(){}
// a variablevar some_var = 1;// some objects var module1 = {};module1.data = { a: 1, b: 2};var module2 = {};
{antipattern}
5 globals...
Wednesday, November 10, 2010
// global object var MYAPP = (function(){ var my = {}; // constructors my.Parent = function(){}; my.Child = function(){}; // a variable my.some_var = 1; // an object container my.modules = {}; // nested objects my.modules.module1 = {}; my.modules.module1.data = { a: 1, b: 2 }; my.modules.module2 = {}; return my;})();
console.log(MYAPP.modules.module1.data.a); // 1
{pattern}1 global!
Wednesday, November 10, 2010
What about encapsulation?
Wednesday, November 10, 2010
function Gadget(){ this.name = 'iPod'; this.stretch = function(){ return 'iPad'; }};
var toy = new Gadget();console.log(toy.name); // `iPod` toy.name = 'Zune'console.log(toy.name); // `Zune` is public console.log(toy.stretch()); // stretch() is public
{antipattern}Wednesday, November 10, 2010
function Gadget(){ var name = 'iPod'; this.getName = function(){ return name; }};
var toy = new Gadget();console.log(toy.getName()); // `iPod`toy.name = 'Zune'console.log(toy.getName()); // `iPod`
Create private member
{pattern}Wednesday, November 10, 2010
function Gadget() { var name = 'iPod'; var upgrade = function(){ return 'iPhone'; }
this.getName = function () { return name; } this.pay = function() { return upgrade(); }};
var toy = new Gadget(); console.log(toy.pay()); // `iPhone`console.log(toy.upgrade()); // `error`
{pattern}
for methods too
Wednesday, November 10, 2010
AdvancedCode reuse patterns
Wednesday, November 10, 2010
vs
Classical vs prototypal inheritance
Wednesday, November 10, 2010
Classical inheritancefunction Parent(name){ this.name = name;};
Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ this.name = name;};
inherit(Child, Parent);
var dad = new Parent('Larry');var kid = new Child('Scott');
console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Wednesday, November 10, 2010
new Parent()
name: Larry__proto__
Parent.prototypesay()
console.log(dad.say());
function(){ return 'My name is ' + this.name;};
Wednesday, November 10, 2010
Default Classical Inheritance pattern
function inherit(C, P) { C.prototype = new P();};
Wednesday, November 10, 2010
new Parent()
name: Larry__proto__
Parent.prototypesay()
new Child()
name: Scott__proto__
console.log(kid.say());
function(){ return 'My name is ' + this.name;};
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};
Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ this.name = name;};
inherit(Child, Parent);
var dad = new Parent('Larry');var kid = new Child('Scott');
console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Drawback: it doesn’t call parent constructor
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};
Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ };
function inherit(C, P) { C.prototype = new P();};
inherit(Child, Parent);
var kid = new Child('Scott');
console.log(kid.say()); // 'My name is undefined'
Drawback: it doesn’t call parent constructor
Wednesday, November 10, 2010
function Child(name){ Parent.apply(this, arguments); };
Pattern Extension: rent a constructor
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ Parent.apply(this, arguments);};
function inherit(C, P){ C.prototype = new P();};inherit(Child, Parent);var dad = new Parent('Larry');var kid = new Child('Scott');console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Pattern Extension: rent a constructor
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ Parent.apply(this, arguments);};
function inherit(C, P){ C.prototype = new P();};inherit(Child, Parent);var dad = new Parent('Larry');var kid = new Child('Scott');console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Drawback: parent constructor is called twice
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ Parent.apply(this, arguments);};
function inherit(C, P){ C.prototype = new P();};inherit(Child, Parent);var dad = new Parent('Larry');var kid = new Child('Scott');console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Drawback: parent constructor is called twice
Wednesday, November 10, 2010
function Parent(name){ this.name = name;};Parent.prototype.say = function(){ return 'My name is ' + this.name;};
function Child(name){ Parent.apply(this, arguments);};
function inherit(C, P){ C.prototype = new P();};inherit(Child, Parent);var dad = new Parent('Larry');var kid = new Child('Scott');console.log(dad.say()); // 'My name is Larry'console.log(kid.say()); // 'My name is Scott'
Drawback: parent constructor is called twice
Wednesday, November 10, 2010
mmmm let’s try with the same prototype
Wednesday, November 10, 2010
function inherit(C, P){ C.prototype = P.prototype;};
Share the same prototype
Wednesday, November 10, 2010
new Parent()
name: Larry__proto__
Parent.prototypesay()
new Child()
name: Scott__proto__
Wednesday, November 10, 2010
Share the same prototype
Inheritance works as expectedConstructor called only onceLow memory footprint
Wednesday, November 10, 2010
Share the same prototype
Child objects can affect other objects
Wednesday, November 10, 2010
function inherit(C, P) { var F = function () {}; F.prototype = P.prototype; C.prototype = new F();};
Enhance the pattern: temporary constructor
Wednesday, November 10, 2010
new Parent()
name: Larry__proto__
Parent.prototypesay()
new Child()
name: Scott__proto__
new F()
__proto__
Wednesday, November 10, 2010
function inherit(C, P) { var F = function () {}; F.prototype = P.prototype; C.prototype = new F(); C.uber = P.prototype; C.prototype.constructor = C;};
The Holy Grail Pattern of classical inheritance
Wednesday, November 10, 2010
We got it!
Wednesday, November 10, 2010
What about Prototypal Inheritance?
Wednesday, November 10, 2010
No more classes, only objects
Wednesday, November 10, 2010
var parent = { name: "Larry", say: function(){ return "My name is " + this.name; }};
var child = object(parent);child.name = 'Scott'
console.log(child.say()); // "Scott"
What we want in prototypal inheritance
Wednesday, November 10, 2010
function object(o) { function F() {} F.prototype = o; return new F();};
Prototypal inheritance function
Wednesday, November 10, 2010
child = new F()
name: Larry__proto__
parent
name: Scottsay()
Wednesday, November 10, 2010
With constructor function
var Parent = function(name){ this.name = name; this.say = function(){ return "My name is " + this.name; }};
var child = object(new Parent("Larry"));child.name = 'Scott'
console.log(child.say()); // "Scott"
Wednesday, November 10, 2010
better classical or prototypal?
Wednesday, November 10, 2010
It depends
Wednesday, November 10, 2010
Goals of inheritance is reuse and reduce duplication
Wednesday, November 10, 2010
isA relationship...Liskov principle...
difficult to tame inheritance...
Wednesday, November 10, 2010
A modern and better approach is to use
Mix-In
Wednesday, November 10, 2010
var Serializer = function () {};Serializer.prototype = { serialize: function () { var output = []; for (key in this) { // append this[key] to output // ... } return output.join(', '); }};
A beahviour...
Wednesday, November 10, 2010
var XmlBuilder = function () {};XmlBuilder.prototype = { toXml: function () { var output = ''; for (key in this) { // append xml of this[key] to output // ... } return output; }};
another beahviour...
Wednesday, November 10, 2010
var Author = function (name, books) { this.name = name || ""; this.books = books || [];}
and an object...
Wednesday, November 10, 2010
augment(Author, Serializer);augment(Author, XmlBuilder);
var author = new Author('Umberto Eco', ['Il nome della rosa', 'Il Pendolo di Foucault']);var serializedString = author.serialize();console.log(serializedString); // name: Umberto Eco, // books: Il nome della rosa,
// Il Pendolo di Foucaultvar xmlString = author.toXml();console.log(xmlString); //<name>Umberto Eco</name> // <book>Il nome della rosa</book> // <book>Il Pendolo di Focault</book>
result!
Wednesday, November 10, 2010
function augment(receivingClass, givingClass) { for (methodName in givingClass.prototype) { if (!receivingClass.prototype[methodName]) { receivingClass.prototype[methodName] =
givingClass.prototype[methodName]; } }}
The recipe
Wednesday, November 10, 2010
AdvancedDesign Patterns
Wednesday, November 10, 2010
Wednesday, November 10, 2010
“A design pattern is a general reusable solution to a commonly occurring problem”
Wednesday, November 10, 2010
JavaScript is not J@#*!
Wednesday, November 10, 2010
creation of objectssubclasses decide which class to instantiate
Factory pattern
Wednesday, November 10, 2010
var BicycleFactory = { createBicycle: function(model){ var bicycle; switch (model) { case 'The Speedster': bicycle = new Speedster(); break; case 'The Lowrider': bicycle = new Lowrider(); break; case 'The Comfort Cruiser': default: bicycle = new ComfortCruiser(); } Interface.ensureImplements(bicycle, Bicycle); bicycle.assemble(); bicycle.wash(); return bicycle; }};var californiaCruisers = new BicycleFactory();var yourNewBike = californiaCruisers.createBicycle('The Speedster');
Wednesday, November 10, 2010
var XMLHttpFactory = function(){ this.createXMLHttp = function(){ if (typeof XMLHttpRequest !== "undefined") { return XMLHttpRequest(); } else if (typeof window.ActiveXObject !== "undefined") { return ActiveXObject("MSXML2.XMLHttp"); } else { alert("XHR Object not in production"); } }};
var xhr = new XMLHttpFactory().createXMLHttp();
A more concrete example...
Wednesday, November 10, 2010
It seems lightly broken....
Wednesday, November 10, 2010
var XMLHttpFactory = function(){ this.createXMLHttp = function(){ if (typeof XMLHttpRequest !== "undefined") { return XMLHttpRequest(); } else if (typeof window.ActiveXObject !== "undefined") { return ActiveXObject("MSXML2.XMLHttp"); } else { alert("XHR Object not in production"); } }};
var xhr = new XMLHttpFactory().createXMLHttp();
Wednesday, November 10, 2010
Chain of Responsibility pattern
Wednesday, November 10, 2010
var XhrStandard = function(){ this.canHandle = function(){ return typeof XMLHttpRequest !== "undefined"; }
this.xhr = function(){ return XMLHttpRequest(); } };
Extract condition and action....
Wednesday, November 10, 2010
var XhrIe = function(){ this.canHandle = function(){ return typeof ActiveXObject !== "undefined"; } this.xhr = function(){ return ActiveXObject("MSXML2.XMLHttp"); } };
another condition and action....
Wednesday, November 10, 2010
var XhrError = function(){ this.canHandle = function(){ return true; } this.xhr = function(){ throw("XHR Object not in production"); } };
and last one condition and action....
Wednesday, November 10, 2010
var XMLHttpFactory = function(){ //... ChainLinks...
var creators = [new XhrStandard(), new XhrIe(), new XhrError()];
this.createXMLHttp = function(){ var creator; for(var i = 0; i < creators.length; ++i){ creator = creators[i]; if(creator.canHandle()) { return creator.xhr(); } } }};
var xhr = new XMLHttpFactory().createXMLHttp();console.log(xhr);
and the engine!
Wednesday, November 10, 2010
Or following the book...
Wednesday, November 10, 2010
var XhrStandard = function(){ this.canHandle = function(){ return typeof XMLHttpRequest !== "undefined"; } this.xhr = function(){ if (this.canHandle()) { return XMLHttpRequest(); } return this.successor.xhr(); } this.addSuccessor = function(successor){ this.successor = successor; return this.successor; } };
Refactored an action...
Wednesday, November 10, 2010
var XhrIe = function(){ this.canHandle = function(){ return typeof ActiveXObject !== "undefined"; } this.xhr = function(){ if (this.canHandle()) { return ActiveXObject("MSXML2.XMLHttp"); } return this.successor.xhr(); } this.addSuccessor = function(successor){ this.successor = successor; return this.successor; } };
other action...
Wednesday, November 10, 2010
var XhrError = function(){ this.canHandle = function(){ return true; } this.xhr = function(){ throw ("XHR Object not in production"); } this.addSuccessor = function(successor){ this.successor = successor; return this.successor; } };
last action...
Wednesday, November 10, 2010
var XMLHttpFactory = function(){ //... ChainLinks... var creator = (function(){ var head = new XhrIe(); head.addSuccessor(new XhrStandard()) .addSuccessor(new XhrError()); return head; })(); this.createXMLHttp = function(){ return creator.xhr(); }};
var xhr = new XMLHttpFactory().createXMLHttp();console.log(xhr);
and the engine!
Wednesday, November 10, 2010
mmm duplication...
Wednesday, November 10, 2010
var XhrIe = function(){ this.canHandle = function(){ return typeof ActiveXObject !== "undefined"; } this.xhr = function(){ if (this.canHandle()) { return ActiveXObject("MSXML2.XMLHttp"); } return this.successor.xhr(); } this.addSuccessor = function(successor){ this.successor = successor; return this.successor; } };
Same for all...
Wednesday, November 10, 2010
var XhrIe = function(){ this.canHandle = function(){ return typeof ActiveXObject !== "undefined"; } this.xhr = function(){ if (this.canHandle()) { return ActiveXObject("MSXML2.XMLHttp"); } return this.successor.xhr(); } this.addSuccessor = function(successor){ this.successor = successor; return this.successor; } };
Similar for all..
Wednesday, November 10, 2010
Template Method pattern
Wednesday, November 10, 2010
... and a little bit of Mix-In
Template Method pattern
Wednesday, November 10, 2010
var ChainLink = function() {}; ChainLink.prototype.exec = function(){ if(this.canHandle()) { return this.doIt(); } return this.successor.exec(); };
ChainLink.prototype.addSuccessor = function(successor){ this.successor = successor; return this.successor; }
Extracted same and similar behaviours....
Wednesday, November 10, 2010
var XhrStandard = augment(function(){ this.canHandle = function(){ return typeof XMLHttpRequest !== "undefined"; } this.doIt = function(){ return XMLHttpRequest(); }; }, ChainLink);
Augment an action...
Wednesday, November 10, 2010
var XhrIe = augment(function(){ this.canHandle = function(){ return typeof ActiveXObject !== "undefined"; } this.doIt = function(){ return this.doIt(); }; }, ChainLink);
another action...
Wednesday, November 10, 2010
var XhrError = augment(function(){ this.canHandle = function(){ return true; }
this.doIt = function(){ throw("XHR Object not in production"); } },ChainLink);
and last one.
Wednesday, November 10, 2010
var XMLHttpFactory = function(){ //... ChainLinks... var creator = (function(){ var head = new XhrIe(); head.addSuccessor(new XhrStandard()) .addSuccessor(new XhrError()); return head; })(); this.createXMLHttp = function(){ return creator.xhr(); }};
var xhr = new XMLHttpFactory().createXMLHttp();console.log(xhr);
and the engine is the same!
Wednesday, November 10, 2010
It’s just a beginning...
Wednesday, November 10, 2010
peep codepeep code
Wednesday, November 10, 2010
Study
Wednesday, November 10, 2010
Wednesday, November 10, 2010
Wednesday, November 10, 2010
“Save it for a rainy day!”
Wednesday, November 10, 2010
Check your code with jslint.com
Wednesday, November 10, 2010
Wednesday, November 10, 2010
@giordanoscalzo
www.slideshare.net/giordano
github.com/gscalzo
Wednesday, November 10, 2010