-
Notifications
You must be signed in to change notification settings - Fork 239
/
closures.js
137 lines (118 loc) · 4.21 KB
/
closures.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
135
136
137
/**
* Closures
*
* Closure is when a function 'remembers' its lexical scope even when the function is executing outside that lexical scope. ~ Kyle Simpson
*
* Closures are useful in hiding the implementation of functionality while still revealing the interface.
*
* Why use Closures?
* http://howtonode.org/why-use-closure
*
* @Reference:
* http://stackoverflow.com/questions/2728278/what-is-a-practical-use-for-a-closure-in-javascript
* https://medium.freecodecamp.com/lets-learn-javascript-closures-66feb44f6a44#.lwnf9bay4
* http://www.bennadel.com/blog/2134-a-random-exploration-of-closure-use-cases-in-javascript.htm
* https://medium.com/written-in-code/practical-uses-for-closures-c65640ae7304#.ukk9dpjxs
* https://medium.com/@nickbalestra/javascripts-lexical-scope-hoisting-and-closures-without-mystery-c2324681d4be#.bg7fk0chp
* https://www.safaribooksonline.com/library/view/javascript-the-good/9780596517748/ch04s15.html
* https://community.risingstack.com/explaining-javascript-closure-scope-chain-examples/
*/
// EXAMPLE 1
function foo() {
var bar = 'bar';
function baz() {
console.log(bar);
}
bam(baz);
}
function bam(baz) {
// Prints 'bar' -- because baz() which is called inside bam's lexical scope has access to `bar` inside foo()
baz(); // bar
}
foo();
// EXAMPLE 2
(function foo() {
var bar = 'bar';
setTimeout(function () {
console.log(bar); // Prints `bar` -- Due to closures - coz setTimout's callback fn has access to foo's lexical scope.
}, 1000)
})();
// EXAMPLE 3
(function foo() {
var bar = 'bar';
$('#btn').click(function () {
console.log(bar); // Prints `bar`
});
})();
// PRACTICAL USE CASES
// 1. To enforce public/private methods. [Classic Module Pattern]
/**
* As you can see there, a is now an object, with a method publicfunction ( a.publicfunction() ) which calls privatefunction,
* which only exists inside the closure.
*
* You can NOT call privatefunction directly (i.e. a.privatefunction() ), just publicfunction().
*/
var a = (function () {
var privateFunction = function () {
console.log('Accessed private method');
};
return {
publicFunction: function () {
privateFunction();
}
}
})();
a.publicFunction(); // Accessed private method.
/**
* For example, imagine you are writing a class of date utility methods and you want to allow users to lookup
* weekday names by index but you don't want them to be able to modify the array of names you use under the hood.
*
* In dateUtil(), note that the days array could simply be stored as a property of the dateUtil object but then it would be
* visible to users of the script and they could even change it if they wanted, without even needing your source code.
* However, since it's enclosed by the anonymous function which returns the date lookup function it is
* only accessible by the lookup function so it is now tamper-proof.
*/
var dateUtil = {
weekdayShort: (function () {
var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
return function (x) {
if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
throw new Error("invalid weekday number");
}
return days[x - 1];
};
}())
};
// 2. To create memoizers.
/**
* You've probably heard of or even implemented the Fibonacci series function a couple of times.
*
* Closures can turn a simple Fibonacci function into a masterpiece.
*
* We are going to start with a classic Fibonacci implementation.
*/
var fibonacci = function (n) {
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
/**
* This one works fine but is awfully slow. It's computing the same value several times.
*
* We can use a memoizer (a closure) to save each computed value for future uses.
*/
var fibonacci = (function ( ) {
var memo = [0, 1];
var fib = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fib(n - 1) + fib(n - 2);
memo[n] = result;
}
return result;
};
return fib;
}( ));
console.log(fibonacci(100));
/**
* Check Crockford's (book)[https://www.safaribooksonline.com/library/view/javascript-the-good/9780596517748/ch04s15.html "Safari Books Online"]
* to find a way to generalize this function into one that memoizes other recursive functions.
*/