Has absolute position but no values set for the location ('auto').
38 |
39 |
Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.
Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.
Click the white box to move the marker to it. Clicking the box also changes the position to absolute (if not already) and sets the position according to the position method.
42 | This is a test page for
43 |
44 | #8135
45 |
46 | which was reported in Firefox when accessing properties
47 | of an XMLHttpRequest object after a network error occurred.
48 |
49 |
Take the following steps:
50 |
51 |
52 | make sure you accessed this page through a web server,
53 |
54 |
55 | stop the web server,
56 |
57 |
58 | open the console,
59 |
60 |
61 | click this
62 |
63 | ,
64 |
65 |
66 | wait for both requests to fail.
67 |
68 |
69 |
70 | Test passes if you get two log lines:
71 |
72 |
73 | the first starting with "abort",
74 |
75 |
76 | the second starting with "complete",
77 |
78 |
79 |
80 |
81 | Test fails if the browser notifies an exception.
82 |
40 | This is a test page for jQuery.readyWait and jQuery.holdReady,
41 | see
42 | #6781
43 | and
44 | #8803.
45 |
46 |
47 | Test for jQuery.holdReady, which can be used
48 | by plugins and other scripts to indicate something
49 | important to the page is still loading and needs
50 | to block the DOM ready callbacks that are registered
51 | with jQuery.
52 |
53 |
54 | Script loaders are the most likely kind of script
55 | to use jQuery.holdReady, but it could be used by
56 | other things like a script that loads a CSS file
57 | and wants to pause the DOM ready callbacks.
58 |
59 |
60 | Expected Result: The text
61 | It Worked!
62 | appears below after about 2 seconds.
63 |
64 |
65 | If there is an error in the console,
66 | or the text does not show up, then the test failed.
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/book/bower_components/jquery/test/unit/deprecated.js:
--------------------------------------------------------------------------------
1 | module("deprecated", { teardown: moduleTeardown });
2 |
3 | if ( jQuery.fn.size ) {
4 | test("size()", function() {
5 | expect(1);
6 | equal( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" );
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/book/bower_components/jquery/test/unit/exports.js:
--------------------------------------------------------------------------------
1 | module("exports", { teardown: moduleTeardown });
2 |
3 | test("amdModule", function() {
4 | expect(1);
5 |
6 | equal( jQuery, amdDefined, "Make sure defined module matches jQuery" );
7 | });
8 |
--------------------------------------------------------------------------------
/book/bower_components/jquery/test/xhtml.php:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/book/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/favicon.ico
--------------------------------------------------------------------------------
/book/images/base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/images/base.png
--------------------------------------------------------------------------------
/book/images/ns1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/images/ns1.png
--------------------------------------------------------------------------------
/book/img/base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/img/base.png
--------------------------------------------------------------------------------
/book/img/ns1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/addyosmani/essential-js-design-patterns/21346c134aa953ba469782372c90e42c36a1f083/book/img/ns1.png
--------------------------------------------------------------------------------
/book/metadata.xml:
--------------------------------------------------------------------------------
1 | Essential JavaScript Design Patterns
2 | Addy Osmani
3 | Creative Commons Attribution Non-Commercial Share Alike 3.0
4 | en-US
5 |
--------------------------------------------------------------------------------
/book/robots.txt:
--------------------------------------------------------------------------------
1 | # robotstxt.org/
2 |
3 | User-agent: *
4 |
--------------------------------------------------------------------------------
/book/scripts/vendor/shBrushJScript.js:
--------------------------------------------------------------------------------
1 | ;(function()
2 | {
3 | // CommonJS
4 | SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
5 |
6 | function Brush()
7 | {
8 | var keywords = 'break case catch class continue ' +
9 | 'default delete do else enum export extends false ' +
10 | 'for function if implements import in instanceof ' +
11 | 'interface let new null package private protected ' +
12 | 'static return super switch ' +
13 | 'this throw true try typeof var while with yield';
14 |
15 | var r = SyntaxHighlighter.regexLib;
16 |
17 | this.regexList = [
18 | { regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings
19 | { regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings
20 | { regex: r.singleLineCComments, css: 'comments' }, // one line comments
21 | { regex: r.multiLineCComments, css: 'comments' }, // multiline comments
22 | { regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
23 | { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
24 | ];
25 |
26 | this.forHtmlScript(r.scriptScriptTags);
27 | };
28 |
29 | Brush.prototype = new SyntaxHighlighter.Highlighter();
30 | Brush.aliases = ['js', 'jscript', 'javascript'];
31 |
32 | SyntaxHighlighter.brushes.JScript = Brush;
33 |
34 | // CommonJS
35 | typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
36 | })();
37 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/0-design-pattern-categorization.es2015.js:
--------------------------------------------------------------------------------
1 | //*******************************************************//
2 | // A brief note on classes
3 | //*******************************************************//
4 |
5 | // Section contains description of ES2015, but not use it.
6 | // I suggest remove the description and put the new examples.
7 |
8 | //********************** Snippet 1 **********************//
9 |
10 | // A car "class"
11 |
12 | // [ES2015+] Below we used new class declaration, using keyword class
13 | // [ES2015+] We used new constructor method and method declaration
14 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance
15 | // [ES2015+] We used new template literals for string interpolation
16 | class Car {
17 | constructor(model) {
18 | this.model = model;
19 | this.color = 'silver';
20 | this.year = '2012';
21 | }
22 |
23 | getInfo() {
24 | return `${this.model} ${this.year}`;
25 | }
26 | }
27 |
28 | //********************** Snippet 2 **********************//
29 |
30 | // Usage:
31 |
32 | // [ES2015+] We used new keyword const for immutable constant declaration
33 | const myCar = new Car('ford');
34 |
35 | myCar.year = '2010';
36 |
37 | console.log(myCar.getInfo());
38 |
39 | // Here the link on Stoyan Stefanov's post, it's a good post.
40 | // But more modern data can be obtained here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
41 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/0-design-pattern-categorization.es5.js:
--------------------------------------------------------------------------------
1 | //*******************************************************//
2 | // A brief note on classes
3 | //*******************************************************//
4 |
5 | //********************** Snippet 1 **********************//
6 |
7 | // A car "class"
8 | function Car( model ) {
9 |
10 | this.model = model;
11 | this.color = "silver";
12 | this.year = "2012";
13 |
14 | this.getInfo = function () {
15 | return this.model + " " + this.year;
16 | };
17 |
18 | }
19 |
20 | //********************** Snippet 2 **********************//
21 |
22 | var myCar = new Car("ford");
23 |
24 | myCar.year = "2010";
25 |
26 | console.log( myCar.getInfo() );
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/1-the-constructor-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //*******************************************************//
2 | // Object Creation
3 | //*******************************************************//
4 |
5 | //********************** Snippet 1 **********************//
6 |
7 | // Each of the following options will create a new empty object:
8 |
9 | var newObject = {};
10 |
11 | // or
12 | var newObject = Object.create( Object.prototype );
13 |
14 | // or
15 | var newObject = new Object();
16 |
17 |
18 | //********************** Snippet 2 **********************//
19 |
20 | // ECMAScript 3 compatible approaches
21 |
22 | // 1. Dot syntax
23 |
24 | // Set properties
25 | newObject.someKey = "Hello World";
26 |
27 | // Get properties
28 | var value = newObject.someKey;
29 |
30 |
31 |
32 | // 2. Square bracket syntax
33 |
34 | // Set properties
35 | newObject["someKey"] = "Hello World";
36 |
37 | // Get properties
38 | var value = newObject["someKey"];
39 |
40 |
41 |
42 | // ECMAScript 5 only compatible approaches
43 | // For more information see: http://kangax.github.com/es5-compat-table/
44 |
45 | // 3. Object.defineProperty
46 |
47 | // Set properties
48 | Object.defineProperty( newObject, "someKey", {
49 | value: "for more control of the property's behavior",
50 | writable: true,
51 | enumerable: true,
52 | configurable: true
53 | });
54 |
55 | // If the above feels a little difficult to read, a short-hand could
56 | // be written as follows:
57 |
58 | var defineProp = function ( obj, key, value ){
59 | var config = {
60 | value: value,
61 | writable: true,
62 | enumerable: true,
63 | configurable: true
64 | };
65 | Object.defineProperty( obj, key, config );
66 | };
67 |
68 | // To use, we then create a new empty "person" object
69 | var person = Object.create( Object.prototype );
70 |
71 | // Populate the object with properties
72 | defineProp( person, "car", "Delorean" );
73 | defineProp( person, "dateOfBirth", "1981" );
74 | defineProp( person, "hasBeard", false );
75 |
76 | console.log(person);
77 | // Outputs: Object {car: "Delorean", dateOfBirth: "1981", hasBeard: false}
78 |
79 |
80 | // 4. Object.defineProperties
81 |
82 | // Set properties
83 | Object.defineProperties( newObject, {
84 |
85 | "someKey": {
86 | value: "Hello World",
87 | writable: true
88 | },
89 |
90 | "anotherKey": {
91 | value: "Foo bar",
92 | writable: false
93 | }
94 |
95 | });
96 |
97 | // Getting properties for 3. and 4. can be done using any of the
98 | // options in 1. and 2.
99 |
100 |
101 | //********************** Snippet 3 **********************//
102 |
103 | // Usage:
104 |
105 | // Create a race car driver that inherits from the person object
106 | var driver = Object.create( person );
107 |
108 | // Set some properties for the driver
109 | defineProp(driver, "topSpeed", "100mph");
110 |
111 | // Get an inherited property (1981)
112 | console.log( driver.dateOfBirth );
113 |
114 | // Get the property we set (100mph)
115 | console.log( driver.topSpeed );
116 |
117 |
118 | //*******************************************************//
119 | // Basic Constructors
120 | //*******************************************************//
121 |
122 | //********************** Snippet 1 **********************//
123 |
124 | function Car( model, year, miles ) {
125 |
126 | this.model = model;
127 | this.year = year;
128 | this.miles = miles;
129 |
130 | this.toString = function () {
131 | return this.model + " has done " + this.miles + " miles";
132 | };
133 | }
134 |
135 | // Usage:
136 |
137 | // We can create new instances of the car
138 | var civic = new Car( "Honda Civic", 2009, 20000 );
139 | var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
140 |
141 | // and then open our browser console to view the
142 | // output of the toString() method being called on
143 | // these objects
144 | console.log( civic.toString() );
145 | console.log( mondeo.toString() );
146 |
147 | //*******************************************************//
148 | // Constructors With Prototypes
149 | //*******************************************************//
150 |
151 | //********************** Snippet 1 **********************//
152 |
153 | function Car( model, year, miles ) {
154 |
155 | this.model = model;
156 | this.year = year;
157 | this.miles = miles;
158 |
159 | }
160 |
161 |
162 | // Note here that we are using Object.prototype.newMethod rather than
163 | // Object.prototype so as to avoid redefining the prototype object
164 | Car.prototype.toString = function () {
165 | return this.model + " has done " + this.miles + " miles";
166 | };
167 |
168 | // Usage:
169 |
170 | var civic = new Car( "Honda Civic", 2009, 20000 );
171 | var mondeo = new Car( "Ford Mondeo", 2010, 5000 );
172 |
173 | console.log( civic.toString() );
174 | console.log( mondeo.toString() );
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/11-the-mixin-pattern.es2015-2.js:
--------------------------------------------------------------------------------
1 | //*******************************************************//
2 | // Mixins
3 | //*******************************************************//
4 |
5 | //********************** Snippet 1 **********************//
6 | // [ES2015+] We used new keyword const for immutable constant declaration
7 | // [ES2015+] We used new method declaration
8 | // [ES2015+] We used new arrow function syntax
9 | // [ES2015+] Below we used new class declaration, using keyword class
10 | // [ES2015+] Class can be used as an expression as well as a statement. As an expression it returns a new class each time it's evaluated.
11 | // [ES2015+] The extends keyword is used to create a class which is a child of another class.
12 | // [ES2015+] The extends clause accepts arbitrary expressions that return classes or constructors
13 | // [ES2015+] All we need to define a mixin is a function that accepts a superclass and creates a new subclass from it, like this:
14 |
15 | const MyMixins = superclass =>
16 | class extends superclass {
17 | moveUp() {
18 | console.log('move up');
19 | }
20 | moveDown() {
21 | console.log('move down');
22 | }
23 | stop() {
24 | console.log('stop! in the name of love!');
25 | }
26 | };
27 |
28 | //********************** Snippet 2 **********************//
29 | // [ES2015+] Below we used new class declaration, using keyword class
30 | // [ES2015+] We used new constructor method and method declaration
31 | // [ES2015+] We used new arrow function syntax
32 | // [ES2015+] We have new pattern implementation with new inheritance
33 |
34 | // A skeleton carAnimator constructor
35 | class CarAnimator {
36 | moveLeft() {
37 | console.log('move left');
38 | }
39 | }
40 | // A skeleton personAnimator constructor
41 | class PersonAnimator {
42 | moveRandomly() {
43 | /*..*/
44 | }
45 | }
46 |
47 | // [ES2015+] Then we can use it in an extends clause like this:
48 | class MyAnimator extends MyMixins(CarAnimator) {}
49 |
50 | // Create a new instance of carAnimator
51 | const myAnimator = new MyAnimator();
52 | myAnimator.moveLeft();
53 | myAnimator.moveDown();
54 | myAnimator.stop();
55 |
56 | // Outputs:
57 | // move left
58 | // move down
59 | // stop! in the name of love!
60 |
61 | //********************** Snippet 3 **********************//
62 | // [ES2015+] Below we used new class declaration, using keyword class
63 | // [ES2015+] We used new constructor method and method declaration
64 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance
65 | // [ES2015+] The extends keyword is used to create a class which is a child of another class.
66 | // [ES2015+] We used new keyword const for immutable constant declaration
67 | // [ES2015+] We used new arrow function syntax
68 |
69 | // Define a simple Car constructor
70 | class Car {
71 | constructor({ model, color }) {
72 | this.model = model || 'no model provided';
73 | this.color = color || 'no colour provided';
74 | }
75 | }
76 |
77 | // Mixin
78 | const Mixin = superclass =>
79 | class extends superclass {
80 | driveForward() {
81 | console.log('drive forward');
82 | }
83 | driveBackward() {
84 | console.log('drive backward');
85 | }
86 | driveSideways() {
87 | console.log('drive sideways');
88 | }
89 | };
90 |
91 | class MyCar extends Mixin(Car) {}
92 |
93 | // Create a new Car
94 | const myCar = new MyCar({
95 | model: 'Ford Escort',
96 | color: 'blue',
97 | });
98 |
99 | // Test to make sure we now have access to the methods
100 | myCar.driveForward();
101 | myCar.driveBackward();
102 |
103 | // Outputs:
104 | // drive forward
105 | // drive backward
106 |
107 | const mySportCar = new MyCar({
108 | model: 'Porsche',
109 | color: 'red',
110 | });
111 |
112 | mySportsCar.driveSideways();
113 |
114 | // Outputs:
115 | // drive sideways
116 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/3-the-revealing-module-pattern.es2015.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 | // [ES2015+] We used new template literals for string interpolation
3 | // [ES2015+] We used new keyword const for immutable constant declaration
4 | // [SE2015+] We used new keyword let, which declares a block scope local variable
5 | // [ES2015+] We used new arrow function syntax
6 | // [ES2015+] We have new pattern implementation with new keywords import and export
7 |
8 | let privateVar = 'Ben Cherry';
9 | const publicVar = 'Hey there!';
10 |
11 | const privateFunction = () => {
12 | console.log(`Name:${privateVar}`);
13 | };
14 |
15 | // [ES2015+] Parentheses are optional when there's only one parameter
16 | const publicSetName = strName => {
17 | privateVar = strName;
18 | };
19 |
20 | const publicGetName = () => {
21 | privateFunction();
22 | };
23 |
24 | // Reveal public pointers to
25 | // private functions and properties
26 | const myRevealingModule = {
27 | setName: publicSetName,
28 | greeting: publicVar,
29 | getName: publicGetName,
30 | };
31 |
32 | // [ES2015+] Default export module, without name
33 | export default myRevealingModule;
34 |
35 | // Usage:
36 | // [ES2015+] The import statement is used to import bindings which are exported by another module.
37 | import myRevealingModule from './myRevealingModule';
38 |
39 | myRevealingModule.setName('Paul Kinlan');
40 |
41 |
42 | //********************** Snippet 2 **********************//
43 | // [ES2015+] We used new keyword const for immutable constant declaration
44 | // [SE2015+] We used new keyword let, which declares a block scope local variable
45 | // [ES2015+] We used new arrow function syntax
46 | // [ES2015+] We have new pattern implementation with new keywords import and export
47 |
48 | let privateCounter = 0;
49 |
50 | const privateFunction = () => {
51 | privateCounter++;
52 | }
53 |
54 | const publicFunction = () => {
55 | publicIncrement();
56 | }
57 |
58 | const publicIncrement = () => {
59 | privateFunction();
60 | }
61 |
62 | // [ES2015+] Equivalent to: => { return privateCounter; }
63 | const publicGetCount = () => privateCounter;
64 |
65 | // Reveal public pointers to
66 | // private functions and properties
67 | const myRevealingModule = {
68 | start: publicFunction,
69 | increment: publicIncrement,
70 | count: publicGetCount
71 | };
72 |
73 | // [ES2015+] Default export module, without name
74 | export default myRevealingModule;
75 |
76 | // Usage:
77 | // [ES2015+] The import statement is used to import bindings which are exported by another module.
78 | import myRevealingModule from './myRevealingModule';
79 |
80 | myRevealingModule.start();
81 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/3-the-revealing-module-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | var myRevealingModule = (function () {
4 |
5 | var privateVar = "Ben Cherry",
6 | publicVar = "Hey there!";
7 |
8 | function privateFunction() {
9 | console.log( "Name:" + privateVar );
10 | }
11 |
12 | function publicSetName( strName ) {
13 | privateVar = strName;
14 | }
15 |
16 | function publicGetName() {
17 | privateFunction();
18 | }
19 |
20 |
21 | // Reveal public pointers to
22 | // private functions and properties
23 |
24 | return {
25 | setName: publicSetName,
26 | greeting: publicVar,
27 | getName: publicGetName
28 | };
29 |
30 | })();
31 |
32 | myRevealingModule.setName( "Paul Kinlan" );
33 |
34 | //********************** Snippet 2 **********************//
35 |
36 | var myRevealingModule = (function () {
37 |
38 | var privateCounter = 0;
39 |
40 | function privateFunction() {
41 | privateCounter++;
42 | }
43 |
44 | function publicFunction() {
45 | publicIncrement();
46 | }
47 |
48 | function publicIncrement() {
49 | privateFunction();
50 | }
51 |
52 | function publicGetCount(){
53 | return privateCounter;
54 | }
55 |
56 | // Reveal public pointers to
57 | // private functions and properties
58 |
59 | return {
60 | start: publicFunction,
61 | increment: publicIncrement,
62 | count: publicGetCount
63 | };
64 |
65 | })();
66 |
67 | myRevealingModule.start();
68 |
69 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/4-the-singleton-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | var mySingleton = (function () {
4 |
5 | // Instance stores a reference to the Singleton
6 | var instance;
7 |
8 | function init() {
9 |
10 | // Singleton
11 |
12 | // Private methods and variables
13 | function privateMethod(){
14 | console.log( "I am private" );
15 | }
16 |
17 | var privateVariable = "Im also private";
18 |
19 | var privateRandomNumber = Math.random();
20 |
21 | return {
22 |
23 | // Public methods and variables
24 | publicMethod: function () {
25 | console.log( "The public can see me!" );
26 | },
27 |
28 | publicProperty: "I am also public",
29 |
30 | getRandomNumber: function() {
31 | return privateRandomNumber;
32 | }
33 |
34 | };
35 |
36 | };
37 |
38 | return {
39 |
40 | // Get the Singleton instance if one exists
41 | // or create one if it doesn't
42 | getInstance: function () {
43 |
44 | if ( !instance ) {
45 | instance = init();
46 | }
47 |
48 | return instance;
49 | }
50 |
51 | };
52 |
53 | })();
54 |
55 | var myBadSingleton = (function () {
56 |
57 | // Instance stores a reference to the Singleton
58 | var instance;
59 |
60 | function init() {
61 |
62 | // Singleton
63 |
64 | var privateRandomNumber = Math.random();
65 |
66 | return {
67 |
68 | getRandomNumber: function() {
69 | return privateRandomNumber;
70 | }
71 |
72 | };
73 |
74 | };
75 |
76 | return {
77 |
78 | // Always create a new Singleton instance
79 | getInstance: function () {
80 |
81 | instance = init();
82 |
83 | return instance;
84 | }
85 |
86 | };
87 |
88 | })();
89 |
90 |
91 | // Usage:
92 |
93 | var singleA = mySingleton.getInstance();
94 | var singleB = mySingleton.getInstance();
95 | console.log( singleA.getRandomNumber() === singleB.getRandomNumber() ); // true
96 |
97 | var badSingleA = myBadSingleton.getInstance();
98 | var badSingleB = myBadSingleton.getInstance();
99 | console.log( badSingleA.getRandomNumber() !== badSingleB.getRandomNumber() ); // true
100 |
101 | // Note: as we are working with random numbers, there is a
102 | // mathematical possibility both numbers will be the same,
103 | // however unlikely. The above example should otherwise still
104 | // be valid.
105 |
106 | //********************** Snippet 2 **********************//
107 |
108 | mySingleton.getInstance = function(){
109 | if ( this._instance == null ) {
110 | if ( isFoo() ) {
111 | this._instance = new FooSingleton();
112 | } else {
113 | this._instance = new BasicSingleton();
114 | }
115 | }
116 | return this._instance;
117 | };
118 |
119 |
120 | //********************** Snippet 3 **********************//
121 |
122 | var SingletonTester = (function () {
123 |
124 | // options: an object containing configuration options for the singleton
125 | // e.g var options = { name: "test", pointX: 5};
126 | function Singleton( options ) {
127 |
128 | // set options to the options supplied
129 | // or an empty object if none are provided
130 | options = options || {};
131 |
132 | // set some properties for our singleton
133 | this.name = "SingletonTester";
134 |
135 | this.pointX = options.pointX || 6;
136 |
137 | this.pointY = options.pointY || 10;
138 |
139 | }
140 |
141 | // our instance holder
142 | var instance;
143 |
144 | // an emulation of static variables and methods
145 | var _static = {
146 |
147 | name: "SingletonTester",
148 |
149 | // Method for getting an instance. It returns
150 | // a singleton instance of a singleton object
151 | getInstance: function( options ) {
152 | if( instance === undefined ) {
153 | instance = new Singleton( options );
154 | }
155 |
156 | return instance;
157 |
158 | }
159 | };
160 |
161 | return _static;
162 |
163 | })();
164 |
165 | var singletonTest = SingletonTester.getInstance({
166 | pointX: 5
167 | });
168 |
169 | // Log the output of pointX just to verify it is correct
170 | // Outputs: 5
171 | console.log( singletonTest.pointX );
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/6-the-mediator-pattern.es2015.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 | // [ES2015+] We used new keyword const for immutable constant declaration
3 |
4 | const mediator = {};
5 |
6 | //********************** Snippet 2 **********************//
7 | // [ES2015+] We used new keyword const for immutable constant declaration
8 | // [ES2015+] We used new arrow function syntax
9 |
10 | const orgChart = {
11 | addNewEmployee() {
12 | // getEmployeeDetail provides a view that users interact with
13 | const employeeDetail = this.getEmployeeDetail();
14 |
15 | // when the employee detail is complete, the mediator (the 'orgchart' object)
16 | // decides what should happen next
17 | // [ES2015+] Parentheses are optional when there is only one parameter
18 | employeeDetail.on('complete', employee => {
19 | // set up additional objects that have additional events, which are used
20 | // by the mediator to do additional things
21 | // [ES2015+] Parentheses are optional when there is only one parameter
22 | const managerSelector = this.selectManager(employee);
23 | managerSelector.on('save', employee => {
24 | employee.save();
25 | });
26 | });
27 | },
28 |
29 | // ...
30 | };
31 |
32 | //********************** Snippet 3 **********************//
33 | // [ES2015+] We used new keyword const for immutable constant declaration
34 | // [ES2015+] Below we used new class declaration, using keyword class
35 | // [ES2015+] We used new constructor method and method declaration
36 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance
37 | // [ES2015+] We used new template literals for string interpolation
38 |
39 | const MenuItem = MyFrameworkView.extend({
40 | events: {
41 | 'click .thatThing': 'clickedIt',
42 | },
43 |
44 | clickedIt(e) {
45 | e.preventDefault();
46 |
47 | // assume this triggers "menu:click:foo"
48 | MyFramework.trigger(`menu:click:${this.model.get('name')}`);
49 | },
50 | });
51 |
52 | // ... somewhere else in the app
53 |
54 | class MyWorkflow {
55 | constructor() {
56 | MyFramework.on('menu:click:foo', this.doStuff, this);
57 | }
58 |
59 | // [ES2015+] The static keyword defines a static method for a class.
60 | // [ES2015+] Static methods are called without instantiating their class and cannot be called through a class instance.
61 | // [ES2015+] Static methods are often used to create utility functions for an application.
62 | static doStuff() {
63 | // instantiate multiple objects here.
64 | // set up event handlers for those objects.
65 | // coordinate all of the objects into a meaningful workflow.
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/6-the-mediator-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | var mediator = {};
4 |
5 | //********************** Snippet 2 **********************//
6 |
7 | var orgChart = {
8 |
9 | addNewEmployee: function(){
10 |
11 | // getEmployeeDetail provides a view that users interact with
12 | var employeeDetail = this.getEmployeeDetail();
13 |
14 | // when the employee detail is complete, the mediator (the 'orgchart' object)
15 | // decides what should happen next
16 | employeeDetail.on("complete", function(employee){
17 |
18 | // set up additional objects that have additional events, which are used
19 | // by the mediator to do additional things
20 | var managerSelector = this.selectManager(employee);
21 | managerSelector.on("save", function(employee){
22 | employee.save();
23 | });
24 |
25 | });
26 | },
27 |
28 | // ...
29 | }
30 |
31 | //********************** Snippet 3 **********************//
32 |
33 | var MenuItem = MyFrameworkView.extend({
34 |
35 | events: {
36 | "click .thatThing": "clickedIt"
37 | },
38 |
39 | clickedIt: function(e){
40 | e.preventDefault();
41 |
42 | // assume this triggers "menu:click:foo"
43 | MyFramework.trigger("menu:click:" + this.model.get("name"));
44 | }
45 |
46 | });
47 |
48 | // ... somewhere else in the app
49 |
50 | var MyWorkflow = function(){
51 | MyFramework.on("menu:click:foo", this.doStuff, this);
52 | };
53 |
54 | MyWorkflow.prototype.doStuff = function(){
55 | // instantiate multiple objects here.
56 | // set up event handlers for those objects.
57 | // coordinate all of the objects into a meaningful workflow.
58 | };
59 |
60 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/7-the-prototype-pattern.es2015.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 | // [ES2015+] We used new keyword const for immutable constant declaration
3 |
4 | const myCar = {
5 | name: 'Ford Escort',
6 |
7 | drive() {
8 | console.log("Weeee. I'm driving!");
9 | },
10 |
11 | panic() {
12 | console.log('Wait. How do you stop this thing?');
13 | },
14 | };
15 |
16 | // Use Object.create to instantiate a new car
17 | const yourCar = Object.create(myCar);
18 |
19 | // Now we can see that one is a prototype of the other
20 | console.log(yourCar.name);
21 |
22 | //********************** Snippet 2 **********************//
23 | // [ES2015+] We used new keyword const for immutable constant declaration
24 | // [ES2015+] We used new template literals for string interpolation
25 |
26 | const vehicle = {
27 | getModel() {
28 | console.log(`The model of this vehicle is..${this.model}`);
29 | },
30 | };
31 |
32 | const car = Object.create(vehicle, {
33 | id: {
34 | value: MY_GLOBAL.nextId(),
35 | // writable:false, configurable:false by default
36 | enumerable: true,
37 | },
38 |
39 | model: {
40 | value: 'Ford',
41 | enumerable: true,
42 | },
43 | });
44 |
45 | //********************** Snippet 3 **********************//
46 | // [ES2015+] Below we used new class declaration, using keyword class
47 | // [ES2015+] We used new constructor method and method declaration
48 | // [ES2015+] We have new pattern implementation with new inheritance
49 | // [ES2015+] Classes are syntactic sugar over JavaScript's prototype-based inheritance
50 | // [ES2015+] We used new keyword const for immutable constant declaration
51 |
52 | class VehiclePrototype {
53 | constructor(model) {
54 | this.model = model;
55 | }
56 |
57 | getModel() {
58 | console.log('The model of this vehicle is..' + this.model);
59 | }
60 |
61 | Clone() {}
62 | }
63 | // [ES2015+] The extends keyword is used to create a class which is a child of another class.
64 | // [ES2015+] A constructor can use the super keyword to call the constructor of the super class.
65 | class Vehicle extends VehiclePrototype {
66 | constructor(model) {
67 | super(model);
68 | }
69 | Clone() {
70 | return new Vehicle(this.model);
71 | }
72 | }
73 |
74 | const car = new Vehicle('Ford Escort');
75 | const car2 = car.Clone();
76 | car2.getModel();
77 |
78 | //********************** Snippet 4 **********************//
79 | // [ES2015+] We used new arrow function syntax
80 | // [ES2015+] We used new keyword const for immutable constant declaration
81 | // [ES2015+] Below we used new class declaration, using keyword class
82 | // [ES2015+] We used new constructor method
83 | // [ES2015+] We still could use Object.prototype for adding new methods, because internally we use the same structure
84 |
85 | const beget = (() => {
86 | class F {
87 | constructor() {}
88 | }
89 |
90 | return proto => {
91 | F.prototype = proto;
92 | return new F();
93 | };
94 | })();
95 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/7-the-prototype-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | var myCar = {
4 |
5 | name: "Ford Escort",
6 |
7 | drive: function () {
8 | console.log( "Weeee. I'm driving!" );
9 | },
10 |
11 | panic: function () {
12 | console.log( "Wait. How do you stop this thing?" );
13 | }
14 |
15 | };
16 |
17 | // Use Object.create to instantiate a new car
18 | var yourCar = Object.create( myCar );
19 |
20 | // Now we can see that one is a prototype of the other
21 | console.log( yourCar.name );
22 |
23 | //********************** Snippet 2 **********************//
24 |
25 | var vehicle = {
26 | getModel: function () {
27 | console.log( "The model of this vehicle is.." + this.model );
28 | }
29 | };
30 |
31 | var car = Object.create(vehicle, {
32 |
33 | "id": {
34 | value: MY_GLOBAL.nextId(),
35 | // writable:false, configurable:false by default
36 | enumerable: true
37 | },
38 |
39 | "model": {
40 | value: "Ford",
41 | enumerable: true
42 | }
43 |
44 | });
45 |
46 | //********************** Snippet 3 **********************//
47 |
48 | var vehiclePrototype = {
49 |
50 | init: function ( carModel ) {
51 | this.model = carModel;
52 | },
53 |
54 | getModel: function () {
55 | console.log( "The model of this vehicle is.." + this.model);
56 | }
57 | };
58 |
59 |
60 | function vehicle( model ) {
61 |
62 | function F() {};
63 | F.prototype = vehiclePrototype;
64 |
65 | var f = new F();
66 |
67 | f.init( model );
68 | return f;
69 |
70 | }
71 |
72 | var car = vehicle( "Ford Escort" );
73 | car.getModel();
74 |
75 | //********************** Snippet 4 **********************//
76 |
77 | var beget = (function () {
78 |
79 | function F() {}
80 |
81 | return function ( proto ) {
82 | F.prototype = proto;
83 | return new F();
84 | };
85 | })();
86 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/8-the-command-pattern.es2015.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 | // [ES2015+] We used new keyword const for immutable constant declaration
3 | // [ES2015+] We used new template literals for string interpolation
4 | // [ES2015+] We used new arrow function syntax
5 |
6 | (() => {
7 | const carManager = {
8 | // request information
9 | requestInfo(model, id) {
10 | return `The information for ${model} with ID ${id} is foobar`;
11 | },
12 |
13 | // purchase the car
14 | buyVehicle(model, id) {
15 | return `You have successfully purchased Item ${id}, a ${model}`;
16 | },
17 |
18 | // arrange a viewing
19 | arrangeViewing(model, id) {
20 | return `You have successfully booked a viewing of ${model} ( ${id} ) `;
21 | },
22 | };
23 | })();
24 |
25 | //********************** Snippet 2 **********************//
26 |
27 | carManager.execute('buyVehicle', 'Ford Escort', '453543');
28 |
29 | //********************** Snippet 3 **********************//
30 |
31 | carManager.execute = function(name) {
32 | return (
33 | carManager[name] &&
34 | carManager[name].apply(carManager, [].slice.call(arguments, 1))
35 | );
36 | };
37 |
38 | //********************** Snippet 4 **********************//
39 |
40 | carManager.execute('arrangeViewing', 'Ferrari', '14523');
41 | carManager.execute('requestInfo', 'Ford Mondeo', '54323');
42 | carManager.execute('requestInfo', 'Ford Escort', '34232');
43 | carManager.execute('buyVehicle', 'Ford Escort', '34232');
44 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/8-the-command-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | (function(){
4 |
5 | var carManager = {
6 |
7 | // request information
8 | requestInfo: function( model, id ){
9 | return "The information for " + model + " with ID " + id + " is foobar";
10 | },
11 |
12 | // purchase the car
13 | buyVehicle: function( model, id ){
14 | return "You have successfully purchased Item " + id + ", a " + model;
15 | },
16 |
17 | // arrange a viewing
18 | arrangeViewing: function( model, id ){
19 | return "You have successfully booked a viewing of " + model + " ( " + id + " ) ";
20 | }
21 |
22 | };
23 |
24 | })();
25 |
26 | //********************** Snippet 2 **********************//
27 |
28 | carManager.execute( "buyVehicle", "Ford Escort", "453543" );
29 |
30 | //********************** Snippet 3 **********************//
31 |
32 | carManager.execute = function ( name ) {
33 | return carManager[name] && carManager[name].apply( carManager, [].slice.call(arguments, 1) );
34 | };
35 |
36 | //********************** Snippet 4 **********************//
37 |
38 | carManager.execute( "arrangeViewing", "Ferrari", "14523" );
39 | carManager.execute( "requestInfo", "Ford Mondeo", "54323" );
40 | carManager.execute( "requestInfo", "Ford Escort", "34232" );
41 | carManager.execute( "buyVehicle", "Ford Escort", "34232" );
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/9-the-facade-pattern.es2015.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 | // [ES2015+] We used new template literals for string interpolation
3 | // [ES2015+] We used new keyword const for immutable constant declaration
4 | // [ES2015+] We used new arrow function syntax
5 |
6 | const addMyEvent = (el, ev, fn) => {
7 | if (el.addEventListener) {
8 | el.addEventListener(ev, fn, false);
9 | } else if (el.attachEvent) {
10 | el.attachEvent(`on${ev}`, fn);
11 | } else {
12 | el[`on${ev}`] = fn;
13 | }
14 | };
15 |
16 | //********************** Snippet 2 **********************//
17 |
18 | bindReady() {
19 | ...
20 | if (document.addEventListener) {
21 | // Use the handy event callback
22 | document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
23 |
24 | // A fallback to window.onload, that will always work
25 | window.addEventListener('load', jQuery.ready, false);
26 |
27 | // If IE event model is used
28 | } else if (document.attachEvent) {
29 |
30 | document.attachEvent('onreadystatechange', DOMContentLoaded);
31 |
32 | // A fallback to window.onload, that will always work
33 | window.attachEvent('onload', jQuery.ready);
34 | ...
35 |
36 |
37 | //********************** Snippet 3 **********************//
38 | // [ES2015+] We have new pattern implementation with new keywords import and export
39 |
40 | const _private = {
41 | i: 5,
42 | get() {
43 | console.log(`current value:${this.i}`);
44 | },
45 | set(val) {
46 | this.i = val;
47 | },
48 | run() {
49 | console.log('running');
50 | },
51 | jump() {
52 | console.log('jumping');
53 | },
54 | };
55 |
56 | // [ES2015+] We used the destructuring assignment syntax that makes it possible to unpack values from data structures into distinct variables.
57 | const module = {
58 | facade({ val, run }) {
59 | _private.set(val);
60 | _private.get();
61 | if (run) {
62 | _private.run();
63 | }
64 | },
65 | };
66 | // [ES2015+] Default export module, without name
67 | export default module;
68 |
69 | // [ES2015+] The import statement is used to import bindings which are exported by another module.
70 | import module from './module';
71 | // Outputs: "current value: 10" and "running"
72 | module.facade({
73 | run: true,
74 | val: 10,
75 | });
76 |
--------------------------------------------------------------------------------
/book/snippets/01-JavaScript-Design-Patterns/9-the-facade-pattern.es5.js:
--------------------------------------------------------------------------------
1 | //********************** Snippet 1 **********************//
2 |
3 | var addMyEvent = function( el,ev,fn ){
4 |
5 | if( el.addEventListener ){
6 | el.addEventListener( ev,fn, false );
7 | }else if(el.attachEvent){
8 | el.attachEvent( "on" + ev, fn );
9 | } else{
10 | el["on" + ev] = fn;
11 | }
12 |
13 | };
14 |
15 |
16 | //********************** Snippet 2 **********************//
17 | bindReady: function() {
18 | ...
19 | if ( document.addEventListener ) {
20 | // Use the handy event callback
21 | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
22 |
23 | // A fallback to window.onload, that will always work
24 | window.addEventListener( "load", jQuery.ready, false );
25 |
26 | // If IE event model is used
27 | } else if ( document.attachEvent ) {
28 |
29 | document.attachEvent( "onreadystatechange", DOMContentLoaded );
30 |
31 | // A fallback to window.onload, that will always work
32 | window.attachEvent( "onload", jQuery.ready );
33 | ...
34 |
35 |
36 |
37 | //********************** Snippet 3 **********************//
38 | var module = (function() {
39 |
40 | var _private = {
41 | i: 5,
42 | get: function() {
43 | console.log( "current value:" + this.i);
44 | },
45 | set: function( val ) {
46 | this.i = val;
47 | },
48 | run: function() {
49 | console.log( "running" );
50 | },
51 | jump: function(){
52 | console.log( "jumping" );
53 | }
54 | };
55 |
56 | return {
57 |
58 | facade: function( args ) {
59 | _private.set(args.val);
60 | _private.get();
61 | if ( args.run ) {
62 | _private.run();
63 | }
64 | }
65 | };
66 | }());
67 |
68 |
69 | // Outputs: "current value: 10" and "running"
70 | module.facade( {run: true, val: 10} );
--------------------------------------------------------------------------------
/book/snippets/02-JavaScript-MV*-Patterns/14-MVC.es2015.js:
--------------------------------------------------------------------------------
1 | //*******************************************************//
2 | // Models
3 | //*******************************************************//
4 | // [ES2015+] We used new keyword const for immutable constant declaration
5 |
6 | //********************** Snippet 1 **********************//
7 | const Photo = Backbone.Model.extend({
8 | // Default attributes for the photo
9 | defaults: {
10 | src: 'placeholder.jpg',
11 | caption: 'A default image',
12 | viewed: false,
13 | },
14 |
15 | // Ensure that each photo created has an `src`.
16 | initialize: function() {
17 | this.set({ src: this.defaults.src });
18 | },
19 | });
20 |
21 | //********************** Snippet 2 **********************//
22 | const PhotoGallery = Backbone.Collection.extend({
23 | // Reference to this collection's model.
24 | model: Photo,
25 |
26 | // Filter down the list of all photos
27 | // that have been viewed
28 | viewed: function() {
29 | return this.filter(function(photo) {
30 | return photo.get('viewed');
31 | });
32 | },
33 |
34 | // Filter down the list to only photos that
35 | // have not yet been viewed
36 | unviewed: function() {
37 | return this.without.apply(this, this.viewed());
38 | },
39 | });
40 |
41 | //*******************************************************//
42 | // Models
43 | //*******************************************************//
44 |
45 | //********************** Snippet 1 **********************//
46 | // [ES2015+] We used new arrow function syntax
47 |
48 | const buildPhotoView = (photoModel, photoController) => {
49 | const base = document.createElement('div');
50 | const photoEl = document.createElement('div');
51 |
52 | base.appendChild(photoEl);
53 |
54 | const render = () => {
55 | // We use a templating library such as Underscore
56 | // templating which generates the HTML for our
57 | // photo entry
58 | photoEl.innerHTML = _.template('#photoTemplate', {
59 | src: photoModel.getSrc(),
60 | });
61 | };
62 |
63 | photoModel.addSubscriber(render);
64 |
65 | photoEl.addEventListener('click', () => {
66 | photoController.handleEvent('click', photoModel);
67 | });
68 |
69 | const show = () => {
70 | photoEl.style.display = '';
71 | };
72 |
73 | const hide = () => {
74 | photoEl.style.display = 'none';
75 | };
76 |
77 | return {
78 | showView: show,
79 | hideView: hide,
80 | };
81 | };
82 |
83 |
84 | //********************** Snippet 2 **********************//
85 |