forked from vasanthk/js-bits
-
Notifications
You must be signed in to change notification settings - Fork 0
/
factory-functions.js
134 lines (104 loc) · 3.47 KB
/
factory-functions.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Factory Functions
*
* @Reference:
* https://www.youtube.com/watch?v=ImwrezYhw4w
* http://atendesigngroup.com/blog/factory-functions-javascript
*
*/
// ES6 classes vs Factory functions
// With classes -- Be wary
class Dog {
constructor() {
this.sound = 'woof';
}
talk() {
console.log(this.sound);
}
}
const sniffles = new Dog();
sniffles.talk(); // Outputs: 'woof'
// Here's the issue
$('button').click(sniffles.talk); // This will not work since - the `this` in talk() now refers to the DOM element selected by $(button) and not sniffles.
// Workaround -- explicit binding
$('button').click(sniffles.talk.bind(sniffles));
// Or in ES6 -- `this` inside an arrow function is always inherited from the enclosing scope.
$('button').click(() => sniffles.talk());
// Factory functions
const dog = () => {
const sound = 'woof';
return {
talk: () => console.log(sound) // We are not using `this` at all.
};
};
const sniffles = dog();
sniffles.talk(); // Outputs: 'woof'
$('button').click(sniffles.talk); // Works -- Outputs: 'woof'
// Constructor functions vs Factory functions
// The basic difference is that a constructor function is used with the new keyword
// (which causes JavaScript to automatically create a new object, set `this` within the function to that object, and return the object):
var objFromConstructor = new ConstructorFunction();
// A factory function is called like a "regular" function:
var objFromFactory = factoryFunction();
// But for it to be considered a "factory" it would need to return a new instance of some object:
// you wouldn't call it a "factory" function if it just returned a boolean or something.
// This does not happen automatically like with new, but it does allow more flexibility for some cases.
// In a really simple example the functions referenced above might look something like this:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
// someMethod() inside obj would lead to each object returned hold a different copy of someMethod which is something that we might not want.
// This is where using `new` and `prototype` inside the factory function would help.
};
// other code to manipulate obj in some way here
return obj;
}
// Factory functions: Encapsulation using private properties
function Car () {
// private variable
var location = 'Denver'; // PRIVATE
function year() { // PRIVATE
self.year = new Date().getFullYear();
}
var self = {
make: 'Honda',
model: 'Accord',
color: '#cc0000',
paint: function(color){
self.color = color;
}
};
if (!self.year){
year();
}
return self;
}
var myCar = Car();
// Factory functions: Dynamic objects
// Since we can have public/private functions we can use if/else statements to easily manipulate our object structure.
// This gives ultimate flexibility to allow the root function ambiguity and allow parameters to determine what the object returned should be.
function Address (param) {
var self = {};
if (param === 'dev'){
self = {
state: 'Colorado',
saveToLog: function(){
// write info to a log file
}
};
} else {
self = {
state: 'Colorado'
};
}
return self;
}
var devAddress = Address('dev');
var productionAddress = Address();