Javascript patterns

2,967 views

Published on

javascript design patterns oop inheritance

0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,967
On SlideShare
0
From Embeds
0
Number of Embeds
29
Actions
Shares
0
Downloads
92
Comments
0
Likes
4
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

×