JavaScript Patterns
Stoyan Stefanov, Yahoo!
@stoyanstefanov




Ajax Experience, Boston 2009
3:25 p.m. Sept 15, 2009
About me
•  Yahoo! Search
•  Yahoo! Exceptional
   Performance
•  YSlow 2.0 architect
•  http://smush.it
•  Books, article...
Types of patterns

•  OO Design Patterns
 (gang of four)
•  JavaScript-specific
   coding patterns
•  Anti-patterns
In this session…
•  Object creation patterns
•  Code reuse patterns
•  Functional patterns
•  More on object creation
•  D...
Object creation patterns
#
Two ways to create objects
•  Object literal
•  Constructor functions



  {}      vs.   new
Object literal
var adam = {}; // clean 
slate 

adam.name = “Adam”; 
adam.say = function() { 
  return “I am ” + 
this.nam...
Object literal
var adam = { 
  name: “Adam”, 
  say: function() { 
    return “I am ” + this.name; 
  } 
}; 
Using a constructor


var adam = new Person(“Adam”); 
adam.say(); // “I am Adam” 
Constructor functions
var Person = function(name) { 

  this.name = name; 
  this.say = function() { 
    return “I am ” +...
Constructor functions
var Person = function(name) { 
  // var this = {}; 
  this.name = name; 
  this.say = function() { 
...
Naming convention

MyConstructor 
myFunction 
Enforcing new 
function Person() {  
  var that = (this === window) ? {} : this; 


  that.name = name; 
  that.say = func...
Enforcing new 
this instanceof Person 

this instanceof arguments.callee 



                           ES5
              ...
Prototype
var Person = function(name) { 
  this.name = name; 
}; 
Person.prototype.say = function() { 
  return “I am ” + ...
How is the prototype used?

>>> var adam = new Person('Adam'); 
>>> adam.name; 
"Adam" 
>>> adam.say(); 
"I am Adam" 
If you want to reuse it,
add it to the prototype
Code reuse patterns
Inheritance – friend or foe


“Prefer object composition
to class inheritance”
Gang of 4
Borrowing methods pattern

•  call() and apply() 

notmyobj.doStuff.call(myobj, param1, p2, p3) 
notmyobj.doStuff.apply(my...
Example: borrowing from Array
function f() { 
   var args = [].slice.call(arguments, 1, 3); 
   return args; 
} 

>>> f(1,...
Inheritance by copying properties
function extend(parent, child) { 
  var i, child = child || {}; 
  for (i in parent) { 
...
Mixins
function mixInThese() { 
  var arg, prop, child = {}; 
  for (arg = 0; arg < arguments.length; arg++) { 
    for (p...
var cake = mixInThese( 
 {eggs: 2, large: true},  
 {butter: 1, salted: true}, 
 {flour: “3 cups”}, 
 {sugar: “sure!”} 
); 
Classical inheritance
function Parent(){ 
  this.name = 'Adam'; 
} 
Parent.prototype.say = function(){ 
  return this.name...
Option 1

function inherit(C, P) { 
  C.prototype = new P(); 
} 

ECMA standard
Option 2 – rent-a-constructor
function C(a, c, b, d) { 
  P.call(this, arguments); 
} 
•  Advantage – passes arguments
whe...
Option 3 – rent + prototype
function C(a, c, b, d) { 
  P.call(this, arguments); 
} 
C.prototype = new P(); 
Option 4
function inherit(C, P) { 
  C.prototype = P.prototype; 
} 
•  Advantage: everybody shares the
same prototype
•  D...
Option 5
function inherit(C, P) { 
  var F = function(){}; 
  F.prototype = P.prototype; 
  C.prototype = new F(); 
} 
•  ...
Option 5 + super

function inherit(C, P) { 
  var F = function(){}; 
  F.prototype = P.prototype; 
  C.prototype = new F()...
Option 5 + super + constructor
reset
function inherit(C, P) { 
  var F = function(){}; 
  F.prototype = P.prototype; 
  C....
Prototypal inheritance

•  by Douglas Crockford
•  no class-like constructors
•  objects inherit from objects
•  via the p...
Prototypal inheritance
function object(o) { 
  function F(){} 
  F.prototype = o; 
  return new F(); 
                    ...
Prototypal inheritance

>>> var parent = {a: 1}; 
>>> var child = object(parent); 
>>> child.a; 
1 
>>> child.hasOwnProper...
Functions
Functions are objects
Self-executable functions

(function(){ 
   var a = 1; 
   var b = 2; 
   alert(a + b); 
})(); 
Self-executable functions

(function(a, b){ 
  var c = a + b; 
  alert(c); 
})(1, 2); 
Callbacks
function test(a, b, fn) { 
    fn(a, b); 
} 

test(1, 2, myFunc); 

test(1, 2, function(one, two){ 
    console....
Callback pattern example

document.addEventListener( 
   'click',  
   animateAndWowUser,  
   false 
); 
Callback pattern example
var thePlotThickens = function(){ 
  console.log('500ms later...'); 
}; 
setTimeout(thePlotThicke...
Returning functions
function setup() { 
    alert(1); 
    return function() { 
        alert(2); 
    }; 
} 
var my = set...
Returning functions
function setup() { 
    var count = 0; 
    return function() { 
        return ++count; 
    }; 
} 
v...
Self-overwriting functions
function next() { 
    var count = 1; 
    next = function() { 
        return ++count; 
    };...
Lazy function definition
function lazy() { 
    var result = 2 + 2; 
    lazy = function() { 
        return result; 
    ...
Function properties
function myFunc(param){ 
    if (!myFunc.cache) { 
        myFunc.cache = {}; 
    } 
    if (!myFunc....
Init-time branching
// BEFORE 
var addListener = function(el, type, fn) {  

  // w3c 
  if (typeof window.addEventListene...
Init-time branching
var addListener;  

if (typeof window.addEventListener === 'function') {  
  addListener = function(el...
More object creation patterns
Private/privileged
function MyConstr() { 
    var a = 1; 
    this.sayAh = function() { 
        return a; 
    }; 
} 

>>...
Declaring dependencies
YAHOO.properties.foo = function() 
{ 
  var Event = YAHOO.util.Event, 
      Dom   = YAHOO.util.Dom...
Namespacing

var myApp = {}; 
myApp.someObj = {}; 
myApp.someObj.someFunc =  
              function()
{}; 
Namespacing

function namespace(){…} 

>>> namespace(‘my.name.space’)
                              
>>> typeof my.name.sp...
Chaining
var o = { 
  v: 1, 
  increment: function() { 
    this.v++; 
    return this; 
  }, 
  add: function(v) { 
    t...
Configuration objects
myPerson(last, first, dob, 
address) 

vs.

var conf = { 
    first: 'Bruce', 
    last: 'Wayne' 
};...
Static members – public
function MyMath() { 
  // math here... 
} 

MyMath.PI = 3.14; 
MyMath.E  = 2.7; 
Module pattern
MYAPP.namespace('modules.foo'); 
MYAPP.modules.foo = function() { 
  var a = 1; 
  return { 
    getA: func...
Design Patterns
Singleton

var mysingleton = {}; 

•  It’s as simple as that
Singleton v.2 (classical)
var my1 = new Single(); 
var my2 = new Single(); 
>>> my1 === my2 
true 

•  How to make this wo...
Singleton v.2 - option 1
var Single = function() { 
  if (typeof Single.instance === “object”) { 
    return Single.instan...
… option 2 (closure)
function Single() { 

  var instance = this;  

  // add more to this… 

  Single = function (){ 
   ...
Factory
var Polygon = function() {}; 
var triangle = Polygon.factory(‘Triangle’); 
var circle   = Polygon.factory(‘Circle’...
And one more thing…
Run JSLint




•  http://jslint.com
•  Integrate with your editor
JSLint
•  missing semi-colons
•  missing curly brackets
•  undeclared vars
•  trailing commas
•  unreachable code
•  for-i...
Thank you!

More…
http://jspatterns.com
http://slideshare.net/stoyan
http://jsmag.com column
JavaScript Patterns
JavaScript Patterns
Upcoming SlideShare
Loading in...5
×

JavaScript Patterns

25,414

Published on

Slides from Ajax Experience 2009. In this session:
- Object creation patterns
- Code reuse patterns
- Functional patterns
- More on object creation
- Design patterns

Some example patterns: object creation with literals and constructos, prototypes, inheritance and other code reuse patterns, lazy definition, callbacks, singleton, factory, classical and prototypal inheritance, namespaces, chaining, modules, static methods, private and privileged members

For more information, see:
http://jspatterns.com
My column in the JavaScript Magazine (http://jsmag.com)
Blog: http://phpied.com

Published in: Technology
3 Comments
141 Likes
Statistics
Notes
  • Nice, these patterns make javascript more elegant and powerful. I love it.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Page 30 is wrong.
    It's supposed to be 'apply' not 'call'

    function C(a, b, c, d) {
    P.apply(this, arguments);
    }
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • nice presentation, help me a lot to understand java

    http://www.homeauvi.com
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total Views
25,414
On Slideshare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
1,433
Comments
3
Likes
141
Embeds 0
No embeds

No notes for slide

JavaScript Patterns

  1. 1. JavaScript Patterns Stoyan Stefanov, Yahoo! @stoyanstefanov Ajax Experience, Boston 2009 3:25 p.m. Sept 15, 2009
  2. 2. About me •  Yahoo! Search •  Yahoo! Exceptional Performance •  YSlow 2.0 architect •  http://smush.it •  Books, articles •  http://phpied.com
  3. 3. Types of patterns •  OO Design Patterns (gang of four) •  JavaScript-specific coding patterns •  Anti-patterns
  4. 4. In this session… •  Object creation patterns •  Code reuse patterns •  Functional patterns •  More on object creation •  Design patterns
  5. 5. Object creation patterns
  6. 6. #
  7. 7. Two ways to create objects •  Object literal •  Constructor functions {} vs. new
  8. 8. Object literal var adam = {}; // clean  slate  adam.name = “Adam”;  adam.say = function() {    return “I am ” +  this.name;  }; 
  9. 9. Object literal var adam = {    name: “Adam”,    say: function() {      return “I am ” + this.name;    }  }; 
  10. 10. Using a constructor var adam = new Person(“Adam”);  adam.say(); // “I am Adam” 
  11. 11. Constructor functions var Person = function(name) {    this.name = name;    this.say = function() {      return “I am ” + this.name;    };  }; 
  12. 12. Constructor functions var Person = function(name) {    // var this = {};    this.name = name;    this.say = function() {      return “I am ” + this.name;    };    // return this;  }; 
  13. 13. Naming convention MyConstructor  myFunction 
  14. 14. Enforcing new  function Person() {     var that = (this === window) ? {} : this;    that.name = name;    that.say = function() {      return “I am ” + that.name;    };    return that;   }  
  15. 15. Enforcing new  this instanceof Person  this instanceof arguments.callee  ES5 FTW
  16. 16. Prototype var Person = function(name) {    this.name = name;  };  Person.prototype.say = function() {    return “I am ” + this.name;  }; 
  17. 17. How is the prototype used? >>> var adam = new Person('Adam');  >>> adam.name;  "Adam"  >>> adam.say();  "I am Adam" 
  18. 18. If you want to reuse it, add it to the prototype
  19. 19. Code reuse patterns
  20. 20. Inheritance – friend or foe “Prefer object composition to class inheritance” Gang of 4
  21. 21. Borrowing methods pattern •  call() and apply()  notmyobj.doStuff.call(myobj, param1, p2, p3)  notmyobj.doStuff.apply(myobj, [param1, p2, p3])  
  22. 22. Example: borrowing from Array function f() {     var args = [].slice.call(arguments, 1, 3);     return args;  }  >>> f(1, 2, 3, 4, 5, 6)  2,3  [].slice.call   can also be Array.prototype.slice.call 
  23. 23. Inheritance by copying properties function extend(parent, child) {    var i, child = child || {};    for (i in parent) {      child[i] = parent[i];    }    return child;  } 
  24. 24. Mixins function mixInThese() {    var arg, prop, child = {};    for (arg = 0; arg < arguments.length; arg++) {      for (prop in arguments[arg]) {        child[prop] = arguments[arg][prop];      }    }    return child;  } 
  25. 25. var cake = mixInThese(   {eggs: 2, large: true},    {butter: 1, salted: true},   {flour: “3 cups”},   {sugar: “sure!”}  ); 
  26. 26. Classical inheritance function Parent(){    this.name = 'Adam';  }  Parent.prototype.say = function(){    return this.name;  };  function Child(){}  inherit(Child, Parent); 
  27. 27. Option 1 function inherit(C, P) {    C.prototype = new P();  }  ECMA standard
  28. 28. Option 2 – rent-a-constructor function C(a, c, b, d) {    P.call(this, arguments);  }  •  Advantage – passes arguments when creating an object •  Drawback – won’t inherit from the prototype
  29. 29. Option 3 – rent + prototype function C(a, c, b, d) {    P.call(this, arguments);  }  C.prototype = new P(); 
  30. 30. Option 4 function inherit(C, P) {    C.prototype = P.prototype;  }  •  Advantage: everybody shares the same prototype •  Drawback: everybody shares the same prototype 
  31. 31. Option 5 function inherit(C, P) {    var F = function(){};    F.prototype = P.prototype;    C.prototype = new F();  }  •  Only inherits properties/ methods of the prototype
  32. 32. Option 5 + super function inherit(C, P) {    var F = function(){};    F.prototype = P.prototype;    C.prototype = new F();    C.uber = P.prototype;  } 
  33. 33. Option 5 + super + constructor reset function inherit(C, P) {    var F = function(){};    F.prototype = P.prototype;    C.prototype = new F();    C.uber = P.prototype;    C.prototype.constructor = C;  } 
  34. 34. Prototypal inheritance •  by Douglas Crockford •  no class-like constructors •  objects inherit from objects •  via the prototype
  35. 35. Prototypal inheritance function object(o) {    function F(){}    F.prototype = o;    return new F();  ES5 }  FTW
  36. 36. Prototypal inheritance >>> var parent = {a: 1};  >>> var child = object(parent);  >>> child.a;  1  >>> child.hasOwnProperty(“a”);  false 
  37. 37. Functions
  38. 38. Functions are objects
  39. 39. Self-executable functions (function(){     var a = 1;     var b = 2;     alert(a + b);  })(); 
  40. 40. Self-executable functions (function(a, b){    var c = a + b;    alert(c);  })(1, 2); 
  41. 41. Callbacks function test(a, b, fn) {      fn(a, b);  }  test(1, 2, myFunc);  test(1, 2, function(one, two){      console.log(arguments);  }); 
  42. 42. Callback pattern example document.addEventListener(   'click',    animateAndWowUser,    false  ); 
  43. 43. Callback pattern example var thePlotThickens = function(){    console.log('500ms later...');  };  setTimeout(thePlotThickens, 500);  // anti‐pattern  setTimeout("thePlotThickens()",  500); 
  44. 44. Returning functions function setup() {      alert(1);      return function() {          alert(2);      };  }  var my = setup(); // alerts 1   my(); // alerts 2 
  45. 45. Returning functions function setup() {      var count = 0;      return function() {          return ++count;      };  }  var next = setup();  next(); // 1  next(); // 2 
  46. 46. Self-overwriting functions function next() {      var count = 1;      next = function() {          return ++count;      };      return count;  }  next(); // 1  next(); // 2 
  47. 47. Lazy function definition function lazy() {      var result = 2 + 2;      lazy = function() {          return result;      };      return lazy();  }  lazy(); // 4  lazy(); // 4 
  48. 48. Function properties function myFunc(param){      if (!myFunc.cache) {          myFunc.cache = {};      }      if (!myFunc.cache[param]) {          var result = {}; // …          myFunc.cache[param] = result;      }      return myFunc.cache[param];  } 
  49. 49. Init-time branching // BEFORE  var addListener = function(el, type, fn) {     // w3c    if (typeof window.addEventListener === 'function') {       el.addEventListener(type, fn, false);     // IE    } else if (typeof document.attachEvent === 'function') {      el.attachEvent('on' + type, fn);     // older browsers    } else {        el['on' + type] = fn;     }   };  
  50. 50. Init-time branching var addListener;   if (typeof window.addEventListener === 'function') {     addListener = function(el, type, fn) {       el.addEventListener(type, fn, false);     };   } else if (typeof document.attachEvent === 'function')  {    addListener = function(el, type, fn) {       el.attachEvent('on' + type, fn);    };   } else {    addListener = function(el, type, fn) {         el['on' + type] = fn;    };   }  
  51. 51. More object creation patterns
  52. 52. Private/privileged function MyConstr() {      var a = 1;      this.sayAh = function() {          return a;      };  }  >>> new MyConstr().sayAh();  1 
  53. 53. Declaring dependencies YAHOO.properties.foo = function()  {    var Event = YAHOO.util.Event,        Dom   = YAHOO.util.Dom;    // ...  }(); 
  54. 54. Namespacing var myApp = {};  myApp.someObj = {};  myApp.someObj.someFunc =                 function() {}; 
  55. 55. Namespacing function namespace(){…}  >>> namespace(‘my.name.space’)   >>> typeof my.name.space  “object” 
  56. 56. Chaining var o = {    v: 1,    increment: function() {      this.v++;      return this;    },    add: function(v) {      this.v += v;      return this;    },    shout: function(){      alert(this.v);    }  };  >>> o.increment().add(3).shout() // 5 
  57. 57. Configuration objects myPerson(last, first, dob,  address)  vs. var conf = {      first: 'Bruce',      last: 'Wayne'  };  myPerson(conf); 
  58. 58. Static members – public function MyMath() {    // math here...  }  MyMath.PI = 3.14;  MyMath.E  = 2.7; 
  59. 59. Module pattern MYAPP.namespace('modules.foo');  MYAPP.modules.foo = function() {    var a = 1;    return {      getA: function(){        return a;      }    };  }(); 
  60. 60. Design Patterns
  61. 61. Singleton var mysingleton = {};  •  It’s as simple as that
  62. 62. Singleton v.2 (classical) var my1 = new Single();  var my2 = new Single();  >>> my1 === my2  true  •  How to make this work?
  63. 63. Singleton v.2 - option 1 var Single = function() {    if (typeof Single.instance === “object”) {      return Single.instance;    }    Single.instance = this;  };  •  Drawback – the instance property is public
  64. 64. … option 2 (closure) function Single() {    var instance = this;     // add more to this…    Single = function (){      return instance;    };  } 
  65. 65. Factory var Polygon = function() {};  var triangle = Polygon.factory(‘Triangle’);  var circle   = Polygon.factory(‘Circle’);  Polygon.Triangle = function(){};  Polygon.Circle   = function(){};  Polygon.factory = function(name) {    if (typeof Polygon[name] === “function”) {      return new Polygon[name]();     }  }; 
  66. 66. And one more thing…
  67. 67. Run JSLint •  http://jslint.com •  Integrate with your editor
  68. 68. JSLint •  missing semi-colons •  missing curly brackets •  undeclared vars •  trailing commas •  unreachable code •  for-in loops •  …
  69. 69. Thank you! More… http://jspatterns.com http://slideshare.net/stoyan http://jsmag.com column
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×