JavaScript Patterns

32,797 views
31,444 views

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
142 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
32,797
On SlideShare
0
From Embeds
0
Number of Embeds
766
Actions
Shares
0
Downloads
1,459
Comments
3
Likes
142
Embeds 0
No embeds

No notes for slide

JavaScript Patterns

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

×