|
| 1 | +--- |
| 2 | +chapter : js101 |
| 3 | +section: 12 |
| 4 | +title: Closures |
| 5 | +attribution: jQuery Fundamentals |
| 6 | +--- |
| 7 | + |
| 8 | +Closures are an extension of the concept of scope -- functions have access to |
| 9 | +variables that were available in the scope where the function was created. If |
| 10 | +that’s confusing, don’t worry: closures are generally best understood by |
| 11 | +example. |
| 12 | + |
| 13 | +In the functions section, we saw how functions have access to changing |
| 14 | +variable values. The same sort of behavior exists with functions defined within |
| 15 | +loops -- the function "sees" the change in the variable's value even after the |
| 16 | +function is defined, resulting in all clicks alerting 5. |
| 17 | + |
| 18 | +<div class="example" markdown="1"> |
| 19 | +How to lock in the value of i? |
| 20 | + |
| 21 | + /* this won't behave as we want it to; */ |
| 22 | + /* every click will alert 5 */ |
| 23 | + for (var i=0; i<5; i++) { |
| 24 | + $('<p>click me</p>').appendTo('body').click(function() { |
| 25 | + alert(i); |
| 26 | + }); |
| 27 | + } |
| 28 | +</div> |
| 29 | + |
| 30 | +<div class="example" markdown="1"> |
| 31 | +Locking in the value of i with a closure |
| 32 | + |
| 33 | + /* fix: “close” the value of i inside createFunction, so it won't change */ |
| 34 | + var createFunction = function(i) { |
| 35 | + return function() { alert(i); }; |
| 36 | + }; |
| 37 | + |
| 38 | + for (var i=0; i<5; i++) { |
| 39 | + $('<p>click me</p>').appendTo('body').click(createFunction(i)); |
| 40 | + } |
| 41 | +</div> |
| 42 | + |
| 43 | +Closures can also be used to resolve issues with the this keyword, which is |
| 44 | +unique to each scope: |
| 45 | + |
| 46 | +<div class="example" markdown="1"> |
| 47 | +Using a closure to access inner and outer object instances simultaneously |
| 48 | + |
| 49 | + var outerObj = { |
| 50 | + myName : 'outer', |
| 51 | + outerFunction : function () { |
| 52 | + // provide a reference to outerObj through innerFunction's closure |
| 53 | + var self = this; |
| 54 | + |
| 55 | + var innerObj = { |
| 56 | + myName : 'inner', |
| 57 | + innerFunction : function () { |
| 58 | + console.log(self.myName, this.myName); // logs 'outer inner' |
| 59 | + } |
| 60 | + }; |
| 61 | + |
| 62 | + innerObj.innerFunction(); |
| 63 | + |
| 64 | + console.log(this.myName); // logs 'outer' |
| 65 | + } |
| 66 | + }; |
| 67 | + |
| 68 | + outerObj.outerFunction(); |
| 69 | +</div> |
| 70 | + |
| 71 | +This mechanism can be particularly useful when dealing with callbacks, though |
| 72 | +in those cases, it is often better to use `Function.bind`, which will avoid any |
| 73 | +overhead associated with scope traversal. |
0 commit comments