├── .gitignore ├── README.md ├── essentials ├── 1-single-var-pattern.js ├── 2-for-loops.js ├── 3-for-in-loops.js ├── 4-(not)augmenting-built-in-prototypes.js ├── 5-switch-pattern.js ├── 6-avoiding-implied-typecasting.js ├── 7-number-conversions-with-parseInt.js ├── 8-coding-conventions.js └── 9-naming-conventions.js ├── functions ├── 1-background.js ├── 10-curry.js ├── 2-callback-pattern.js ├── 3-returning-functions.js ├── 4-self-defining-functions.js ├── 5-immediate-functions.js ├── 6-immediate-object-initialization.js ├── 7-init-time-branching.js ├── 8-function-properties-a-memoization-pattern.js └── 9-configuration-objects.js ├── literals-and-constructors ├── 1-object-literal.js ├── 2-custom-constructor-functions.js ├── 3-patterns-for-enforcing-new.js ├── 4-array-literal.js ├── 5-json.js ├── 6-regular-expression-literal.js ├── 7-primitive-wrappers.js └── 8-error-objects.js └── object-creation-patterns ├── 1-namespace-pattern.js └── 2-declaring-dependencies.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Numerous always-ignore extensions 2 | *.diff 3 | *.err 4 | *.orig 5 | *.log 6 | *.rej 7 | *.swo 8 | *.swp 9 | *.vi 10 | *~ 11 | *.sass-cache 12 | 13 | # OS or Editor folders 14 | .DS_Store 15 | Thumbs.db 16 | .cache 17 | .project 18 | .settings 19 | .tmproj 20 | *.esproj 21 | nbproject 22 | *.sublime-project 23 | *.sublime-workspace 24 | 25 | # Folders to ignore 26 | .hg 27 | .svn 28 | .CVS 29 | .idea 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a repository to reference the code examples in the excellent book "JavaScript Patterns". 2 | 3 | JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 4 | 5 | Thanks to the folks at O'Reilly Media, Inc. for their permission to do this. 6 | -------------------------------------------------------------------------------- /essentials/1-single-var-pattern.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Single var Pattern */ 6 | 7 | // Example 1 - multiple declarations 8 | 9 | function func() { 10 | var a = 1, 11 | b = 2, 12 | sum = a + b, 13 | myobject = {}, 14 | i, 15 | j; 16 | 17 | // function body... 18 | } 19 | 20 | 21 | // Example 2 - assigning DOM references 22 | 23 | function updateElement() { 24 | var el = document.getElementById('result'), 25 | style = el.style; 26 | 27 | // do something with el and style... 28 | } 29 | -------------------------------------------------------------------------------- /essentials/2-for-loops.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* for Loops */ 6 | 7 | // Example 1 - with caching 8 | 9 | for (var i = 0, max = myarray.length; i < max; i++) { 10 | // do something with myarray[i] 11 | } 12 | 13 | 14 | // Example 2 - with caching and using single var pattern 15 | 16 | function looper() { 17 | var i = 0, 18 | max, 19 | myarray = []; 20 | // ... 21 | } 22 | 23 | 24 | for (i = 0, max = myarray.length; i < max; i++) { 25 | // do something with myarray[i] 26 | } 27 | 28 | // Example 3 - 1st variation of the for pattern with micro-optimizations 29 | 30 | var i, myarray = []; 31 | 32 | for (i = myarray.length; i--;) { 33 | // do something with myarray[i] 34 | } 35 | 36 | 37 | // Example 4 - 2nd variation of the for pattern with micro-optimizations 38 | 39 | var myarray = [], 40 | i = myarray.length; 41 | 42 | while (i--) { 43 | // do something with myarray[i] 44 | } 45 | -------------------------------------------------------------------------------- /essentials/3-for-in-loops.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* for-in Loops */ 6 | 7 | // Example 1 - filtering 8 | 9 | for (var i in man) { 10 | if (man.hasOwnProperty(i)) { // filter 11 | console.log(i, ':', man[i]); 12 | } 13 | } 14 | 15 | 16 | // Example 2 - call from Object.prototype 17 | 18 | for (var i in man) { 19 | if (Object.prototype.hasOwnProperty.call(man, i)) { // filter 20 | console.log(i, ':', man[i]); 21 | } 22 | } 23 | 24 | 25 | // Example 3 - call from Object.prototype with caching 26 | 27 | var i, 28 | hasOwn = Object.prototype.hasOwnProperty; 29 | for (i in man) { 30 | if (hasOwn.call(man, i)) { // filter 31 | console.log(i, ':', man[i]); 32 | } 33 | } 34 | 35 | 36 | // Example 4 - formatting variation of the above 37 | 38 | // Warning: doesn't pass JSLint 39 | var i, 40 | hasOwn = Object.prototype.hasOwnProperty; 41 | for (i in man) if (hasOwn.call(man, i)) { // filter 42 | console.log(i, ':', man[i]); 43 | } 44 | -------------------------------------------------------------------------------- /essentials/4-(not)augmenting-built-in-prototypes.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* (Not) Augmenting Built-In Prototypes */ 6 | 7 | // Example - polyfilling missing functionality 8 | 9 | if (typeof Object.protoype.myMethod !== 'function') { 10 | Object.protoype.myMethod = function () { 11 | // implementation... 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /essentials/5-switch-pattern.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Switch Pattern */ 6 | 7 | // Example - improved readability and robustness 8 | 9 | var inspect_me = 0, 10 | result = ''; 11 | 12 | switch (inspect_me) { 13 | case 0: 14 | result = 'zero'; 15 | break; 16 | case 1: 17 | result = 'one'; 18 | break; 19 | default: 20 | result = 'unknown'; 21 | } 22 | -------------------------------------------------------------------------------- /essentials/6-avoiding-implied-typecasting.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Avoiding Implied Typecasting */ 6 | 7 | // Example 1 - use === and !== 8 | 9 | var zero = 0; 10 | if (zero === false) { 11 | // not executing because zero is 0, not false 12 | } 13 | 14 | 15 | // Example 2 - avoid eval() 16 | 17 | // antipattern 18 | var property = 'name'; 19 | alert(eval('obj.' + property)); 20 | 21 | // preferred 22 | var property = 'name'; 23 | alert(obj[property]); 24 | 25 | 26 | // Example 3 - avoid passing strings to setInterval() and setTimeout() and the Function() constructor 27 | 28 | // antipatterns 29 | setTimeout('myFunc()', 1000); 30 | setTimeout('myFunc(1, 2, 3)', 1000); 31 | 32 | // preferred 33 | setTimeout(myFunc, 1000); 34 | setTimeout(function () { 35 | myFunc(1, 2, 3); 36 | }, 1000); 37 | 38 | 39 | // Example 4 - if you must choose, use the Function() constructor over eval() 40 | 41 | (function () { 42 | var local = 1; 43 | eval('local = 3; console.log(local)'); // logs 3 44 | console.log(local); // logs 3 45 | }()); 46 | 47 | (function () { 48 | var local = 1; 49 | Function('console.log(typeof local);')(); // logs undefined 50 | }()); 51 | -------------------------------------------------------------------------------- /essentials/7-number-conversions-with-parseInt.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Number Conversions with parseInt() */ 6 | 7 | // Example 1 - provide the radix argument to parseInt() to avoid unexpected results 8 | 9 | var month = '06', 10 | year = '09'; 11 | month = parseInt(month, 10); // 6 12 | year = parseInt(year, 10); // 9 with radix, 0 without it 13 | 14 | 15 | // Example 2 - alternative ways to convert a string to a number 16 | 17 | +'08' // result is 8 18 | Number('08') // 8 19 | -------------------------------------------------------------------------------- /essentials/8-coding-conventions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Coding Conventions */ 6 | 7 | // Example 1 - indentation 8 | 9 | function outer(a, b) { 10 | var c = 1, 11 | d = 2, 12 | inner; 13 | if (a > b) { 14 | inner = function () { 15 | return { 16 | r: c - d 17 | }; 18 | }; 19 | } else { 20 | inner = function () { 21 | return { 22 | r: c + d 23 | }; 24 | }; 25 | } 26 | return inner; 27 | } 28 | 29 | 30 | // Example 2 - always use curly braces 31 | 32 | // bad practice 33 | for (var i = 0; i < 10; i += 1) 34 | alert(i); 35 | 36 | // better 37 | for (var i = 0; i < 10; i += 1) { 38 | alert(i); 39 | } 40 | 41 | // bad 42 | if (true) 43 | alert(1); 44 | else 45 | alert(2); 46 | 47 | // better 48 | if (true) { 49 | alert(1); 50 | } else { 51 | alert(2); 52 | } 53 | 54 | 55 | // Example 3 - opening brace location on the same line as the previous statement 56 | 57 | // warning: unexpected return value 58 | function func() { 59 | return 60 | { 61 | name: "Batman" 62 | }; 63 | } 64 | 65 | // better 66 | function func() { 67 | return { 68 | name: "Batman" 69 | }; 70 | } 71 | 72 | 73 | // Example 4 - white space 74 | 75 | // antipattern 76 | // missing or inconsistent spaces 77 | // make the code confusing 78 | var d= 0, 79 | a =b+1; 80 | if (a&& b&&c) { 81 | d=a %c; 82 | a+= d; 83 | } 84 | 85 | // generous and consistent spacing 86 | // makes the code easier to read 87 | // allowing it to "breathe" 88 | var d = 0, 89 | a = b + 1; 90 | if (a && b && c) { 91 | d = a % c; 92 | a += d; 93 | } 94 | -------------------------------------------------------------------------------- /essentials/9-naming-conventions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Naming Conventions */ 6 | 7 | // Example 1 - capitalize constructor functions to set them apart 8 | 9 | function MyConstructor() {...} 10 | function myFunction() {...} 11 | 12 | 13 | // Example 2 - separating words using common conventions 14 | 15 | new Myconstructor(); // upper camel case for constructors 16 | getFirstName(); // lower camel case for functions and methods 17 | first_name // using underscores to separate words 18 | lastName // or lower camel case for variables 19 | 20 | // Example 3 - other naming patterns 21 | 22 | // all caps separated by underscores to denote variables that shouldn't change (constants) 23 | var PI = 3.14, 24 | MAX_WIDTH = 800; 25 | 26 | // prefix with an underscore to denote privacy 27 | var person = { 28 | getName: function () { 29 | return this._getFirst() + ' ' + this._getLast(); 30 | }, 31 | _getFirst: function () { 32 | // ... 33 | }, 34 | _getLast: function () { 35 | // ... 36 | } 37 | }; 38 | 39 | // varieties to the _private convention: 40 | getElements_(); // trailing underscore to mean private 41 | _getRelatives(); // one underscore prefix for _protected properties 42 | __getFirstName(); // and two for __private 43 | -------------------------------------------------------------------------------- /functions/1-background.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Background */ 6 | 7 | // Example 1 - named function expression 8 | 9 | var add = function add(a, b) { 10 | return a + b; 11 | }; 12 | 13 | 14 | // Example 2 - unnamed function expression, function expression or anonymous function 15 | 16 | var add = function (a, b) { 17 | return a + b; 18 | }; 19 | 20 | 21 | // Example 3 - function declaration 22 | 23 | function foo() { 24 | // function body goes here 25 | } 26 | 27 | 28 | // Example 4 - passing a function object as a parameter 29 | 30 | // this is a function expression, 31 | // pased as an argument to the function 'callMe' 32 | callMe(function () { 33 | // I am an unnamed function expression 34 | // also known as an anonymous function 35 | }); 36 | 37 | // this is a named function expression 38 | callMe(function me() { 39 | // I am a named function expression 40 | // and my name is 'me' 41 | }); 42 | 43 | // another function expression 44 | var myobject = { 45 | say: function () { 46 | // I am a function expression 47 | } 48 | }; 49 | 50 | 51 | // Example 5 - function declarations can only appear in "program code" 52 | 53 | // global scope 54 | function foo() {} 55 | 56 | function local() { 57 | // local scope 58 | function bar() {} 59 | return bar; 60 | } 61 | 62 | 63 | // Example 6 - availability of the read-only name property 64 | 65 | function foo() {} // declaration 66 | var bar = function () {}; // expression 67 | var baz = function baz() {}; // named expression 68 | 69 | foo.name; // 'foo' 70 | bar.name; // '' 71 | baz.name; // 'baz' 72 | 73 | 74 | // Example 7 - function declarations get both their declaration and definition hoisted 75 | 76 | // antipattern 77 | // for illustration only 78 | 79 | // global functions 80 | function foo() { 81 | alert('global foo'); 82 | } 83 | 84 | function bar() { 85 | alert('global bar'); 86 | } 87 | 88 | function hoistMe() { 89 | 90 | console.log(typeof foo); // 'function' 91 | console.log(typeof bar); // 'undefined' 92 | 93 | foo(); // 'local foo' 94 | bar(); // TypeError: bar is not a function 95 | 96 | // function declaration: 97 | // variable 'foo' and its implementation both get hoisted 98 | 99 | function foo() { 100 | alert('local foo'); 101 | } 102 | 103 | // function expression: 104 | // only variable 'bar' gets hoisted 105 | // not the implementation 106 | var bar = function () { 107 | alert('local bar'); 108 | }; 109 | 110 | } 111 | hoistMe(); 112 | -------------------------------------------------------------------------------- /functions/10-curry.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Curry */ 6 | 7 | // Example 1 - Function "application" (invokation) with the apply() method 8 | 9 | // define a function 10 | var sayHi = function (who) { 11 | return 'Hello' + (who ? ', ' + who : '') + '!'; 12 | }; 13 | 14 | // invoke a function 15 | sayHi(); // 'Hello' 16 | sayHi('world'); // 'Hello, world!' 17 | 18 | // apply a function 19 | sayHi.apply(null, ['hello']); // 'Hello, hello!' 20 | 21 | 22 | /* Example 2 - Invoking a object's method is just like applying a function and 23 | sending the object as the first argument. */ 24 | 25 | var alien = { 26 | sayHi: function (who) { 27 | return 'Hello' + (who ? ', ' + who : '') + '!'; 28 | } 29 | }; 30 | 31 | alien.sayHi('world'); // 'Hello, world!' 32 | sayHi.apply(alien, ['humans']); // 'Hello, humans!' 33 | 34 | 35 | /* Example 3 - The call() method does the same as apply() but it takes arguments 36 | separated by commas. */ 37 | 38 | // the second is more efficient, saves an array 39 | sayHi.apply(alien, ['humans']); // 'Hello, humans!' 40 | sayHi.call(alien, 'humans'); // 'Hello, humans!' 41 | 42 | 43 | // Example 4 - Partially applying arguments. 44 | 45 | // for illustration purposes 46 | // not valid JavaScript 47 | 48 | // we have this function 49 | function add(x, y) { 50 | return x + y; 51 | } 52 | 53 | // and we know the arguments 54 | add(5, 4); 55 | 56 | // step 1 -- substitute one argument 57 | function add(5, y) { 58 | return 5 + y; 59 | } 60 | 61 | // step 2 -- substitute the other argument 62 | function add(5, 4) { 63 | return 5 + 4; 64 | } 65 | 66 | /* Example 5 - Partial application gives us another function, which can then be 67 | called with the other arguments. */ 68 | 69 | 70 | var add = function (x, y) { 71 | return x + y; 72 | }; 73 | 74 | // full application 75 | add.apply(null, [5, 4]); // 9 76 | 77 | // partial application 78 | var newadd = add.partialApply(null, [5]); 79 | // applying an argument to the new function 80 | newadd.apply(null, [4]); // 9 81 | 82 | 83 | // Example 6 - Curried add() 84 | 85 | // a curried add() 86 | // accepts partial list of arguments 87 | function add(x, y) { 88 | var oldx = x, oldy = y; 89 | if (typeof oldy === 'undefined') { // partial 90 | return function (newy) { 91 | return oldx + newy; 92 | }; 93 | } 94 | // full application 95 | return x + y; 96 | } 97 | 98 | // test 99 | 100 | typeof add(5); // 'function' 101 | add(3)(4); // 7 102 | 103 | // create and store a new function 104 | var add2000 = add(2000); 105 | add2000(10); // 2010 106 | 107 | 108 | // Example 7 - A compact version 109 | 110 | // a curried add 111 | // accepts partial list of arguments 112 | function add(x, y) { 113 | if (typeof y === 'undefined') { // partial 114 | return function (y) { 115 | return x + y; 116 | }; 117 | } 118 | // full application 119 | return x + y; 120 | } 121 | 122 | 123 | /* Example 8 - A function to transform a function into a new one that accepts 124 | partial parameters. */ 125 | 126 | function schonfinkelize(fn) { 127 | var slice = Array.prototype.slice, 128 | stored_args = slice.call(arguments, 1); 129 | return function () { 130 | var new_args = slice.call(arguments), 131 | args = stored_args.concat(new_args); 132 | return fn.apply(null, args); 133 | }; 134 | } 135 | 136 | 137 | // Example 9 - Testing the schonfinkelize() function 138 | 139 | // a normal function 140 | function add(x, y) { 141 | return x + y; 142 | } 143 | 144 | // curry a function to get a new function 145 | var newadd = schonfinkelize(add, 5); 146 | newadd(4); // 9 147 | 148 | // another option -- call the new function directly 149 | schonfinkelize(add, 6)(7); // 13 150 | 151 | 152 | // Example 10 - More usage examples 153 | 154 | // a normal function 155 | function add(a, b, c, d, e) { 156 | return a + b + c + d + e; 157 | } 158 | 159 | // works with any number of arguments 160 | schonfinkelize(add, 1, 2, 3)(5, 5); // 16 161 | 162 | // two-step currying 163 | var addOne = schonfinkelize(add, 1); 164 | addOne(10, 10, 10, 10); // 41 165 | var addSix = schonfinkelize(addOne, 2, 3); 166 | addSix(5, 5); // 16 167 | -------------------------------------------------------------------------------- /functions/2-callback-pattern.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Callback Pattern */ 6 | 7 | // Example 1 - passing a function as a parameter, making it a callback function 8 | 9 | function writeCode(callback) { 10 | // do something... 11 | callback(); 12 | // ... 13 | } 14 | 15 | function introduceBugs() { 16 | // ... make bugs 17 | } 18 | 19 | writeCode(introduceBugs); 20 | 21 | 22 | // Example 2 - refactoring, using the callback pattern, from: 23 | 24 | var findNodes = function () { 25 | var i = 100000, // big, heavy loop 26 | nodes = [], // stores the result 27 | found; // the next node found 28 | while (i) { 29 | i -= 1; 30 | // complex logic here... 31 | nodes.push(found); 32 | } 33 | return nodes; 34 | }; 35 | 36 | var hide = function (nodes) { 37 | var i = 0, max = nodes.length; 38 | for (; i < max; i += 1) { 39 | nodes[i].style.display = 'none'; 40 | } 41 | }; 42 | 43 | // executing the functions 44 | hide(findNodes()); 45 | 46 | // to: 47 | 48 | // refactored findNodes() to accept a callback 49 | var findNodes = function (callback) { 50 | var i = 100000, 51 | nodes = [], 52 | found; 53 | 54 | // check if callback is callable 55 | if (typeof callback !== 'function') { 56 | callback = false; 57 | } 58 | 59 | while (i) { 60 | i -= 1; 61 | 62 | // complex logic here... 63 | 64 | // now callback: 65 | if (callback) { 66 | callback(found); 67 | } 68 | 69 | nodes.push(found); 70 | } 71 | return nodes; 72 | }; 73 | 74 | // a callback function 75 | var hide = function (node) { 76 | node.style.display = 'none'; 77 | }; 78 | 79 | // find the nodes and hide them as you go 80 | findNodes(hide); 81 | 82 | // or using an anonymous function 83 | 84 | // passing an anonymous callback 85 | findNodes(function (node) { 86 | node.style.display = 'block'; 87 | }); 88 | 89 | 90 | // Example 3 - proper binding of a callback to an object 91 | 92 | var myapp = {}; 93 | myapp.color = 'green'; 94 | myapp.paint = function (node) { 95 | node.style.color = this.color; 96 | }; 97 | 98 | var findNodes = function (callback) { 99 | // ... 100 | if (typeof callback === 'function') { 101 | callback(found); 102 | } 103 | // ... 104 | }; 105 | 106 | findNodes(myapp.paint, myapp); // oops 107 | 108 | // alternative 1 - pass the object 109 | 110 | findNodes(myapp.paint, myapp); 111 | 112 | var findNodes = function (callback, callback_obj) { 113 | //... 114 | if (typeof callback === 'function') { 115 | callback.call(callback_obj, found); 116 | } 117 | // ... 118 | }; 119 | 120 | // alternative 2 - pass method name as string 121 | 122 | findNodes('paint', myapp); 123 | 124 | var findNodes = function (callback, callback_obj) { 125 | if (typeof callback === 'string') { 126 | callback = callback_obj[callback]; 127 | } 128 | }; 129 | //... 130 | if (typeof callback === 'function') { 131 | callback.call(callback_obj, found); 132 | } 133 | // ... 134 | 135 | 136 | // Example 4 - an example of an asynchronous event listeners 137 | 138 | document.addEventListener('click', console.log, false); 139 | 140 | 141 | // Example 5 - setTimeout() and setInterval() are other examples of the callback pattern 142 | 143 | var thePlotThickens = function () { 144 | console.log('500ms later...'); 145 | }; 146 | setTimeout(thePlotThickens, 500); 147 | -------------------------------------------------------------------------------- /functions/3-returning-functions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Returning Functions */ 6 | 7 | // Example 1 - since functions are objects they can be returned from functions 8 | 9 | var setup = function () { 10 | alert(1); 11 | return function () { 12 | alert(2); 13 | }; 14 | }; 15 | 16 | // using the setup function 17 | var my = setup(); // alerts 1 18 | my(); // alerts 2 19 | 20 | 21 | /* Example 2 - this creates a closure in which the returned function has access to its 22 | container's variables */ 23 | 24 | var setup = function () { 25 | var count = 0; 26 | return function () { 27 | return (count += 1); 28 | }; 29 | }; 30 | 31 | // usage 32 | var next = setup(); 33 | next(); // returns 1 34 | next(); // 2 35 | next(); // 3 36 | 37 | -------------------------------------------------------------------------------- /functions/4-self-defining-functions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Self-Defining Functions */ 6 | 7 | /* Example 1 - overwriting a function definition while defining it, also called lazy function 8 | definition */ 9 | 10 | var scareMe = function () { 11 | alert('Boo!'); 12 | scareMe = function () { 13 | alert('Double boo!'); 14 | }; 15 | }; 16 | 17 | // using the self-defining function 18 | scareMe(); // Boo! 19 | scareMe(); // Double boo! 20 | 21 | 22 | /* Example 2 - drawbacks, properties added to the original function will be lost and if the 23 | function is used with a different name, the redefinition will not happen */ 24 | 25 | // 1. adding a new property 26 | scareMe.property = 'properly'; 27 | 28 | // 2. assigning to a different name 29 | var prank = scareMe; 30 | 31 | // 3. using as a method 32 | var spooky = { 33 | boo: scareMe 34 | }; 35 | 36 | // calling with a new name 37 | prank(); // 'Boo!' 38 | prank(); // 'Boo!' 39 | console.log(prank.property); // 'properly' 40 | 41 | // calling as a method 42 | spooky.boo(); // 'Boo!' 43 | spooky.boo(); // 'Boo!' 44 | console.log(spooky.boo.property); // 'properly' 45 | 46 | // using the self-defined function 47 | scareMe(); // Double boo! 48 | scareMe(); // Double boo! 49 | console.log(scareMe.property); // undefined 50 | -------------------------------------------------------------------------------- /functions/5-immediate-functions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Immediate Functions */ 6 | 7 | // Example 1 - immediate function pattern 8 | 9 | (function () { 10 | alert('watch out!'); 11 | }()); 12 | 13 | 14 | // Example 2 -another flavor of the immediate function pattern, not liked by JSLint 15 | 16 | (function () { 17 | alert('watch out!'); 18 | })(); 19 | 20 | 21 | // Example 3 - create a local scope to avoid leaking variables into the global scope 22 | 23 | (function () { 24 | var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 25 | today = new Date(), 26 | msg = 'Today is ' + days[today.getDay()] + ', ' + today.getDate(); 27 | 28 | alert(msg); 29 | }()); // 'Today is Fri, 13' 30 | 31 | 32 | // Example 4 - passing arguments to an immediate function 33 | 34 | // prints: 35 | // I met Joe Black on Fri Aug 13 2010 23:26:59 GMT-0800 (PST) 36 | 37 | (function (who, when) { 38 | 39 | console.log("I met " + who + " on " + when); 40 | 41 | }("Joe Black", new Date())); 42 | 43 | 44 | // Example 5 - passing the global object so it's accessible through a parameter 45 | 46 | (function (global) { 47 | 48 | // access the global object via 'global' 49 | 50 | }(this)); 51 | 52 | 53 | // Example 6 - returning a value from an immediate functions call 54 | 55 | var result = (function () { 56 | 57 | return 2 + 2; 58 | 59 | }()); 60 | 61 | 62 | // Example 7 - Another syntax when returning a value (not recommended) 63 | 64 | var result = function () { 65 | 66 | return 2 + 2; 67 | 68 | }(); 69 | 70 | 71 | // Example 8 - Yet another syntax when returning a value (not liked by JSLint) 72 | 73 | var result = (function () { 74 | 75 | return 2 + 2; 76 | 77 | })(); 78 | 79 | 80 | /* Example 9 - An immediate function can return any type, in this case, the value of res 81 | stored in a closure */ 82 | 83 | var getResult = (function () { 84 | var res = 2 + 2; 85 | 86 | return function () { 87 | return res; 88 | }; 89 | }()); 90 | 91 | 92 | // Example 10 - Immediate functions can also be used when defining object properties 93 | 94 | var o = { 95 | message: (function () { 96 | var who = 'me', 97 | what = 'call'; 98 | return what + ' ' + who; 99 | }()), 100 | getMsg: function () { 101 | return this.message; 102 | } 103 | }; 104 | // usage 105 | o.getMsg(); // 'call me' 106 | o.message; // 'call me' 107 | 108 | 109 | // Example 11 - Defining modules 110 | 111 | // module1 defined in module1.js 112 | (function () { 113 | 114 | // all the module 1 code ... 115 | 116 | }()); 117 | -------------------------------------------------------------------------------- /functions/6-immediate-object-initialization.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Immediate Object Initialization */ 6 | 7 | // Example 1 - protecting global scope pollution 8 | 9 | ({ 10 | // here you can define setting values 11 | // a.k.a. configuration constants 12 | maxwidth: 600, 13 | maxheight: 400, 14 | 15 | // you can also define utility methods 16 | gimmeMax: function () { 17 | return this.maxwidth + 'x' + this.maxheight; 18 | }, 19 | 20 | // initialize 21 | init: function () { 22 | console.log(this.gimmeMax()); 23 | // more init tasks... 24 | } 25 | }).init(); 26 | 27 | // Example 2 - Other wrappings 28 | 29 | ({...}).init(); 30 | ({...}.init()); 31 | -------------------------------------------------------------------------------- /functions/7-init-time-branching.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Init-Time Branching */ 6 | 7 | /* Example 1 - It's an optimization pattern to avoid reaching the same conclusion on conditions 8 | that won't change */ 9 | 10 | // BEFORE 11 | var utils = { 12 | addListener: function (el, type, fn) { 13 | if (typeof window.addEventListener === 'function') { 14 | el.addEventListener(type, fn, false); 15 | } else if (typeof document.attachEvent === 'function') { // IE 16 | el.attachEvent('on' + type, fn); 17 | } else { // older browsers 18 | el['on' + type] = fn; 19 | } 20 | }, 21 | removeListener: function (el, type, fn) { 22 | // pretty much the same... 23 | } 24 | }; 25 | 26 | // AFTER 27 | 28 | // the interface 29 | var utils = { 30 | addListener: null, 31 | removeListener: null 32 | }; 33 | 34 | // the implementation 35 | if (typeof window.addEventListener === 'function') { 36 | utils.addListener = function (el, type, fn) { 37 | el.addEventListener(type, fn, false); 38 | }; 39 | utils.removeListener = function (el, type, fn) { 40 | el.removeEventListener(type, fn, false); 41 | }; 42 | } else if (typeof document.attachEvent === 'function') { // IE 43 | utils.addListener = function (el, type, fn) { 44 | el.attachEvent('on' + type, fn); 45 | }; 46 | utils.removeListener = function (el, type, fn) { 47 | el.detachEvent('on' + type, fn); 48 | }; 49 | } else { // older browsers 50 | utils.addListener = function (el, type, fn) { 51 | el['on' + type] = fn; 52 | }; 53 | utils.removeListener = function (el, type, fn) { 54 | el['on' + type] = null; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /functions/8-function-properties-a-memoization-pattern.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Function Properties - A Memoization Pattern */ 6 | 7 | // Example 1 - Memoization is the process of caching the results of a function 8 | 9 | var myFunc = function (param) { 10 | if (!myFunc.cache[param]) { 11 | var result = {}; 12 | // ... expensive operation ... 13 | myFunc.cache[param] = result; 14 | } 15 | return myFunc.cache[param]; 16 | }; 17 | 18 | // cache storage 19 | myFunc.cache = {}; 20 | 21 | 22 | // Example 2 - Serializing the arguments and using that as the key to the cache 23 | 24 | var myFunc = function () { 25 | 26 | var cachekey = JSON.stringify(Array.prototype.slice.call(arguments)), 27 | result; 28 | 29 | if (!myFunc.cache[cachekey]) { 30 | result = {}; 31 | // ... expensive operation ... 32 | myFunc.cache[cachekey] = result; 33 | } 34 | return myFunc.cache[cachekey]; 35 | }; 36 | 37 | // cache storage 38 | myFunc.cache = {}; 39 | 40 | 41 | // Example 3 - Using arguments.callee (not allowed in ES5 Strict Mode) 42 | 43 | var myFunc = function (param) { 44 | var f = arguments.callee, 45 | result; 46 | 47 | if (!f.cache[param]) { 48 | result = {}; 49 | // ... expensive operation ... 50 | f.cache[param] = result; 51 | } 52 | return f.cache[param]; 53 | }; 54 | 55 | // cache storage 56 | myFunc.cache = {}; 57 | -------------------------------------------------------------------------------- /functions/9-configuration-objects.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Configuration Objects */ 6 | 7 | // Example 1 - Function that takes a first name and a last name 8 | 9 | function addPerson(first, last) {...} 10 | 11 | 12 | // Example 2 - DOB needs to be stored too and gender and address optionally 13 | 14 | function addPerson(first, last, dob, gender, address) {...} 15 | 16 | 17 | // Example 3 - Username also needs to be added 18 | 19 | addPerson('Bruce', 'Wayne', new Date(), null, null, 'batman'); 20 | 21 | 22 | /* Example 4 - Taking a configuration object solves the function's long signature problem, 23 | you don't have to remember the order of the arguments, you can safely ommit optional 24 | parameters, etc. */ 25 | 26 | var conf = { 27 | username: 'batman', 28 | first: 'Bruce', 29 | last: 'Wayne' 30 | }; 31 | addPerson(conf); 32 | -------------------------------------------------------------------------------- /literals-and-constructors/1-object-literal.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Object Literal */ 6 | 7 | // Example 1 - declaration and initialization with the object literal 8 | 9 | var dog = { 10 | name: 'Benji', 11 | getName: function () { 12 | return this.name; 13 | } 14 | }; 15 | 16 | 17 | // Example 2 - don't use the Object() constructor 18 | 19 | // one way -- using a literal 20 | var car = { goes: 'far' }; 21 | 22 | // another way -- using a built-in constructor 23 | // warning: this is an antipattern 24 | var car = new Object(); 25 | car.goes = 'far'; 26 | -------------------------------------------------------------------------------- /literals-and-constructors/2-custom-constructor-functions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Custom Constructor Functions */ 6 | 7 | // Example 1 - using the constructor's prototype to augment objects 8 | 9 | var Person = function (name) { 10 | this.name = name; 11 | this.say = function () { 12 | return 'I am ' + this.name; 13 | }; 14 | }; 15 | 16 | var adam = new Person('Adam'); 17 | adam.say(); // 'I am Adam' 18 | 19 | // better 20 | 21 | var Person = function (name) { 22 | this.name = name; 23 | }; 24 | 25 | Person.prototype.say = function () { 26 | return 'I am ' + this.name; 27 | }; 28 | 29 | var adam = new Person('Adam'); 30 | adam.say(); // 'I am Adam' 31 | 32 | 33 | // Example 2 - return any object in the constructor 34 | 35 | var Objectmaker = function () { 36 | // this 'name' property will be ignored 37 | // because the constructor 38 | // decides to return another object instead 39 | this.name = "This is it"; 40 | 41 | // creating and returning a new object 42 | var that = {}; 43 | that.name = "And that's that"; 44 | return that; 45 | }; 46 | 47 | var o = new Objectmaker(); 48 | console.log(o.name); // "And that's that" 49 | -------------------------------------------------------------------------------- /literals-and-constructors/3-patterns-for-enforcing-new.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Patterns for enforcing new */ 6 | 7 | // Example 1 - forgetting to use the new keyword when invoking a constructor function 8 | 9 | // constructor 10 | function Waffle() { 11 | this.tastes = 'yummy'; 12 | } 13 | 14 | // a new object 15 | var good_morning = new Waffle(); 16 | console.log(typeof good_morning); // 'object' 17 | console.log(good_morning.tastes); // 'yummy' 18 | 19 | // antipattern: 20 | // forgotten 'new' 21 | var good_morning = Waffle(); 22 | console.log(typeof good_morning); // 'undefined' 23 | console.log(window.tastes); // 'yummy' 24 | 25 | 26 | // Example 2 - using a naming convention, like upper camel case 27 | 28 | // you can tell it's a constructor 29 | function Waffle() { 30 | this.tastes = 'yummy'; 31 | } 32 | 33 | // you can tell it's a function 34 | function alertMe(msg) { 35 | alert('There\'s something you should know: ' + msg); 36 | } 37 | 38 | 39 | // Example 3 - using that, construct the object yourself and return it 40 | 41 | function Waffle() { 42 | var that = {}; 43 | that.tastes = 'yummy'; 44 | return that; 45 | } 46 | 47 | // or just return an object literal 48 | 49 | function Waffle() { 50 | return { 51 | tastes: 'yummy' 52 | }; 53 | } 54 | 55 | var first = new Waffle(), 56 | second = Waffle(); 57 | console.log(first.tastes); // 'yummy' 58 | console.log(second.tastes); // 'yummy' 59 | 60 | // this works but constructed objects will not inherit anything from the constructor's prototype 61 | 62 | 63 | // Example - self-invoking constructor 64 | 65 | function Waffle() { 66 | if (!(this instanceof Waffle)) { 67 | return new Waffle(); 68 | } 69 | this.tastes = 'yummy'; 70 | } 71 | Waffle.prototype.wantAnother = true; 72 | 73 | // testing invocations 74 | var first = new Waffle(), 75 | second = Waffle(); 76 | 77 | console.log(first.tastes); // 'yummy' 78 | console.log(second.tastes); // 'yummy' 79 | console.log(first.wantAnother); // true 80 | console.log(second.wantAnother); // true 81 | -------------------------------------------------------------------------------- /literals-and-constructors/4-array-literal.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Array Literal */ 6 | 7 | // Example 1 - making arrays using the array constructor and array literal 8 | 9 | // array of three elements 10 | // warning: antipattern 11 | var a = new Array('itsy', 'bitsy', 'spider'); 12 | 13 | // the exact same array 14 | var a = ['itsy', 'bitsy', 'spider']; 15 | 16 | console.log(typeof a); // 'object', because arrays are objects 17 | console.log(a.constructor === Array); // true 18 | 19 | 20 | // Example 2 - consistent behavior with the array literal, dynamic behavior with the array constructor 21 | 22 | // an array of one element 23 | var a = [3]; 24 | console.log(a.length); // 1 25 | console.log(a[0]); // 3 26 | 27 | // an array of three elements 28 | var a = new Array(3); 29 | console.log(a.length); // 3 30 | console.log(typeof a[0]); // 'undefined' 31 | 32 | // using array literal 33 | var a = [3.14]; 34 | console.log(a[0]); // 3.14 35 | var a = new Array(3.14); // RangeError: invalid array length 36 | console.log(typeof a); // 'undefined' 37 | 38 | 39 | // Example 3 - using isArray to check for array-ness 40 | 41 | // the typeof operator is insufficient 42 | 43 | console.log(typeof [1, 2]); // 'object' 44 | 45 | // isArray from ECMAScript 5 46 | 47 | Array.isArray([]); // true 48 | 49 | // trying to fool the check 50 | // with an array-like object 51 | Array.isArray({ 52 | length: 1, 53 | '0': 1, 54 | slice: function () {} 55 | }); // false 56 | 57 | // implement isArray method when it's missing 58 | 59 | if (typeof Array.isArray === 'undefined') { 60 | Array.isArray = function (arg) { 61 | return Object.prototype.toString.call(arg) === '[object Array]'; 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /literals-and-constructors/5-json.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* JSON */ 6 | 7 | /* Example 1 - example of a JSON string, property names need to be wrapped in quotes and you 8 | cannot use functions or regular expressions literals. */ 9 | 10 | var foo = { 11 | "name": "value", 12 | "some": [1, 2, 3] 13 | }; 14 | 15 | 16 | // Example 2 - it's best to use the native JSON.parse() method from ES5. 17 | 18 | // an input JSON string 19 | var jstr = '{"mykey": "my value"}'; 20 | 21 | // antipattern 22 | var data = eval('(' + jstr + ')'); 23 | 24 | // preferred 25 | var data = JSON.parse(jstr); 26 | console.log(data.mykey); // 'my value' 27 | 28 | 29 | /* Example 3 - if the native function is unavailable, use the JSON.org library unless you are 30 | already working with a JavaScript library that does the job */ 31 | 32 | /* Using YUI3 */ 33 | 34 | // an input JSON string 35 | var jstr = '{"mykey": "my value"}'; 36 | 37 | // parse the string and turn it into an object 38 | // using a YUI instance 39 | YUI().use('json-parse', function (Y) { 40 | var data = Y.JSON.parse(jstr); 41 | console.log(data.mykey); // "my value" 42 | }); 43 | 44 | /* Using jQuery */ 45 | 46 | // an input JSON string 47 | var jstr = '{"mykey": "my value"}'; 48 | 49 | var data = jQuery.parseJSON(jstr); 50 | console.log(data.mykey); // "my value" 51 | 52 | 53 | /* Example 4 - JSON.stringify() does the opposite. It takes any object or array (or a primitive) and 54 | serializes it into a JSON string */ 55 | 56 | var dog = { 57 | name: "Fido", 58 | dob: new Date(), 59 | legs: [1, 2, 3, 4] 60 | }; 61 | 62 | var jsonstr = JSON.stringify(dog); 63 | 64 | // jsonstr is now: 65 | // {"name":"Fido","dob":"2012-01-01T19:00:00.436Z","legs":[1,2,3,4]} 66 | -------------------------------------------------------------------------------- /literals-and-constructors/6-regular-expression-literal.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Regular Expression Literal */ 6 | 7 | // Example 1 - create a regular expression using the literal or the constructor 8 | 9 | // regular expression literal 10 | var re = /\\/gm; 11 | 12 | // constructor 13 | var re = new RegExp('\\\\', 'gm'); 14 | 15 | 16 | // Example 2 - using the literal helps write more concise code 17 | 18 | var no_letters = 'abc123XYZ'.replace(/[a-z]/gi, ''); 19 | console.log(no_letters); // 123 20 | 21 | 22 | // Example 3 - in ES3, the literal creates an object only once. This behavior has changed in ES5 23 | 24 | function getRE() { 25 | var re = /[a-z]/; 26 | re.foo = 'bar'; 27 | return re; 28 | } 29 | 30 | var reg = getRE(), 31 | re2 = getRE(); 32 | 33 | console.log(reg === re2); // true 34 | reg.foo = 'baz'; 35 | console.log(re2.foo); // 'baz' 36 | -------------------------------------------------------------------------------- /literals-and-constructors/7-primitive-wrappers.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Primitive Wrappers */ 6 | 7 | // Example 1 - primitive wrapper objects can be created using the built-in constructors 8 | 9 | // a primitive number 10 | var n = 100; 11 | console.log(typeof n); // 'number' 12 | 13 | // a Number object 14 | var nobj = new Number(100); 15 | console.log(typeof nobj); // 'object' 16 | 17 | 18 | // Example 2 - the wrapper objects' properties and methods work on primitives too 19 | 20 | // a primitive string be used as an object 21 | var s = 'hello'; 22 | console.log(s.toUpperCase()); // 'HELLO' 23 | 24 | // the value itself can act as an object 25 | 'monkey'.slice(3, 6); // 'key' 26 | 27 | // same for numbers 28 | (22 / 7).toPrecision(3); // '3.14' 29 | 30 | 31 | // Example 3 - use wrapper objects when you want to augment the value and persist state 32 | 33 | // primitive string 34 | var greet = 'Hello there'; 35 | 36 | // primitive is converted to an object 37 | // in order to use the split() method 38 | greet.split(' ')[0]; // 'Hello' 39 | 40 | // attemting to augment a primitive is not an error 41 | greet.smile = true; 42 | 43 | // but it doesn't actually work 44 | typeof greet.smile; // 'undefined' 45 | 46 | 47 | // Example 4 - when used without new, wrapper constructors return a primitive value 48 | 49 | typeof Number(1); // 'number' 50 | typeof Number('1'); // 'number' 51 | typeof Number(new Number()); // 'number' 52 | typeof String(1); // 'string' 53 | typeof Boolean(1); // 'boolean' 54 | -------------------------------------------------------------------------------- /literals-and-constructors/8-error-objects.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Error Objects */ 6 | 7 | // Example - throwing a custom error object 8 | 9 | try { 10 | // something bad happened, throw an error 11 | throw { 12 | name: 'MyErrorType', // custom error type 13 | message: 'oops', 14 | extra: 'This was rather embarrassing', 15 | remedy: genericErrorHandler // who should handle it 16 | }; 17 | } catch (e) { 18 | // inform the user 19 | alert(e.message); // 'oops' 20 | 21 | // gracefully handle the error 22 | e.remedy(); // calls genericErrorHandler() 23 | } 24 | -------------------------------------------------------------------------------- /object-creation-patterns/1-namespace-pattern.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Namespace Pattern */ 6 | 7 | /* Example 1 - instead of polluting the global scope with a lot of functions, objects, 8 | and other variables, like this: */ 9 | 10 | // BEFORE: 5 globals 11 | // Warning: antipattern 12 | 13 | // constructors 14 | function Parent() {} 15 | function Child() {} 16 | 17 | // a variable 18 | var some_var = 1; 19 | 20 | // some objects 21 | var module1 = {}; 22 | module1.data = {a: 1, b: 2}; 23 | var module2 = {}; 24 | 25 | // You can refactor this type of code by creating a single global object for your application 26 | 27 | // AFTER: 1 global 28 | 29 | // global object 30 | var MYAPP = {}; 31 | 32 | // constructors 33 | MYAPP.Parent = function () {}; 34 | MYAPP.Child = function () {}; 35 | 36 | // a variable 37 | MYAPP.some_var = 1; 38 | 39 | // an object container 40 | MYAPP.modules = {}; 41 | 42 | // nested objects 43 | MYAPP.modules.module1 = {}; 44 | MYAPP.modules.module1.data = {a: 1, b: 2}; 45 | MYAPP.modules.module2 = {}; 46 | 47 | 48 | // Example 2 - checking if the namespace exists before defining it 49 | 50 | // unsafe 51 | var MYAPP = {}; 52 | 53 | // better 54 | if (typeof MYAPP === 'undefined') { 55 | var MYAPP = {}; 56 | } 57 | 58 | // or shorter 59 | var MYAPP = MYAPP || {}; 60 | 61 | 62 | // Example 3 - using a namespace function to take care of the details 63 | 64 | // using a namespace function 65 | MYAPP.namespace('MYAPP.modules.module2'); 66 | 67 | // equivalent to: 68 | // var MYAPP = { 69 | // modules: { 70 | // module2: {} 71 | // } 72 | // }; 73 | 74 | 75 | // Example 4 - an implementation of the namespace function 76 | 77 | var MYAPP = MYAPP || {}; 78 | MYAPP.namespace = function (ns_string) { 79 | var parts = ns_string.split('.'), 80 | parent = MYAPP, 81 | i; 82 | 83 | // strip redundant leading global 84 | if (parts[0] === 'MYAPP') { 85 | parts = parts.slice(1); 86 | } 87 | 88 | for (i = 0; i < parts.length; i += 1) { 89 | // create a property if it doesn't exist 90 | if (typeof parent[parts[i]] === 'undefined') { 91 | parent[parts[i]] = {}; 92 | } 93 | parent = parent[parts[i]]; 94 | } 95 | return parent; 96 | }; 97 | 98 | 99 | // Example 5 - how it can be used 100 | 101 | // assign returned value to a local var 102 | var module2 = MYAPP.namespace('MYAPP.modules.module2'); 103 | module2 === MYAPP.modules.module2; // true 104 | 105 | // skip initial 'MYAPP' 106 | MYAPP.namespace('modules.module51'); 107 | 108 | // long namespace 109 | MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property'); 110 | -------------------------------------------------------------------------------- /object-creation-patterns/2-declaring-dependencies.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Patterns, by Stoyan Stefanov (O'Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750. 3 | */ 4 | 5 | /* Declaring Dependencies */ 6 | 7 | // Example 1 - declaring module dependencies at the top of your function 8 | 9 | var myFunction = function () { 10 | // dependencies 11 | var event = YAHOO.util.Event, 12 | dom = YAHOO.util.Dom; 13 | 14 | // use event and dom variables 15 | // for the rest of the function... 16 | }; 17 | 18 | 19 | // Example 2 - it also helps performance by making minified code smaller 20 | 21 | function test1() { 22 | alert(MYAPP.modules.m1); 23 | alert(MYAPP.modules.m2); 24 | alert(MYAPP.modules.m51); 25 | } 26 | 27 | /* 28 | minified test1 body: 29 | alert(MYAPP.modules.m1);alert(MYAPP.modules.m2);alert(MYAPP.modules.m51) 30 | */ 31 | 32 | function test2() { 33 | var modules = MYAPP.modules; 34 | alert(modules.m1); 35 | alert(modules.m2); 36 | alert(modules.m51); 37 | } 38 | 39 | /* 40 | minified test2 body: 41 | var a=MYAPP.modules;alert(a.m1);alert(a.m2);alert(a.m51) 42 | */ 43 | --------------------------------------------------------------------------------