Skip to content

Instantly share code, notes, and snippets.

@GA-MEB
Last active June 29, 2016 14:54

Revisions

  1. GA-MEB revised this gist Jun 29, 2016. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions js-closures-teachback.md
    Original file line number Diff line number Diff line change
    @@ -62,17 +62,15 @@ var myFunction = function(){
    myFunction();
    ```

    <!--
    **Poll: What value will `myFunction` print when it is invoked?**

    - 5
    - 10
    - undefined
    -->

    <!-- Ask a student from each group to give their justification. -->

    The answer is '10'.
    <!-- The answer is '10'. -->

    <!-- Draw a diagram here of function scopes and variable references. -->

  2. GA-MEB revised this gist Jun 29, 2016. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions js-closures-teachback.md
    Original file line number Diff line number Diff line change
    @@ -62,11 +62,13 @@ var myFunction = function(){
    myFunction();
    ```

    <!--
    **Poll: What value will `myFunction` print when it is invoked?**
    - 5
    - 10
    - undefined
    -->

    <!-- Ask a student from each group to give their justification. -->

  3. GA-MEB revised this gist Jun 29, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions js-closures-teachback.md
    Original file line number Diff line number Diff line change
    @@ -68,11 +68,11 @@ myFunction();
    - 10
    - undefined

    _Ask a student from each group to give their justification._
    <!-- Ask a student from each group to give their justification. -->

    The answer is '10'.

    _Draw a diagram here of function scopes and variable references._
    <!-- Draw a diagram here of function scopes and variable references. -->

    `a` is defined both inside and outside the function,
    and both definitions have different values.
  4. GA-MEB revised this gist Jun 29, 2016. 1 changed file with 209 additions and 1 deletion.
    210 changes: 209 additions & 1 deletion js-closures-teachback.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,209 @@
    ...
    # Lesson : Scope and Closures in Javascript

    ## Prerequisites

    - Pass by reference/value
    - Functions

    ## Learning Objectives

    - Determine the value of a given variable using knowledge of functional scope.
    - Demonstrate how function scope limits access to variables.
    - Use a simple javascript closure to make a counter.
    - Create a more complicated closure that returns a collection of functions.

    ## Lesson Notes

    By now you should already be familiar with defining and invoking functions.
    You’ve probably seen things like this.
    `a` is defined inide the function and is available inside the function.

    ```js
    var myFunction = function(){
    var a = 10;
    console.log(a);
    };
    myFunction(); // 10
    ```

    You’ve also probably seen things like this.
    Even though `a` is not defined inside the function,
    it is accessible from within the function.

    ```js
    var a = 5;
    var myFunction = function(){
    console.log(a);
    };
    myFunction(); // 5
    ```

    What about the reverse?
    If we define `a` inside the function, can we access it from outside?

    ```js
    var myFunction = function(){
    var a = 10;
    };
    myFunction();
    console.log(a); // ERROR
    ```

    No, we can't.

    What happens here?

    ```js
    var a = 5;
    var myFunction = function(){
    var a = 10;
    console.log(a);
    };
    myFunction();
    ```

    **Poll: What value will `myFunction` print when it is invoked?**

    - 5
    - 10
    - undefined

    _Ask a student from each group to give their justification._

    The answer is '10'.

    _Draw a diagram here of function scopes and variable references._

    `a` is defined both inside and outside the function,
    and both definitions have different values.
    When our code tries to find a value for `a`,
    it first checks the set of variables inside of the function
    (i.e. the function’s scope).
    If it doesn’t find a value, it then checks the next outermost scope.

    In JavaScript, new scopes can only be created by defining new functions.
    The golden rule is to think of scope as bring 'one-way glass',
    like in those cop shows.
    You can always see 'out', but never 'in'... Almost.
    There is a loophole in this system that allows us to get inside a function's
    scope, but only when the function is invoked.

    Consider a function defined inside another function.

    ```js
    var outerFunction = function(){
    var a = 100;
    var innerFunction = function(){
    console.log(a);
    };
    innerFunction();
    };
    outerFunction(); // 100
    ```

    Invoking the outer function also invokes the inner function,
    which prints the value of `a`.
    Clearly, the `console.log` inside `innerFunction` has access to `a`,
    since it’s in an outer scope.
    What if we were to return `innerFunction` out of `outerFunction`,
    and invoke it there? What would happen?

    ```js
    var outerFunction = function(){
    var a = 100;
    var innerFunction = function(){
    console.log(a);
    };
    return innerFunction;
    };
    var refToInnerFunc = outerFunction(); // `outerFunction` returns a reference to the function `innerFunction`
    refToInnerFunc();
    ```

    Since `innerFunction` has `a` in its scope,
    by passing out a reference to `innerFunction`,
    we give ourselves the ability to (indirectly) interact with `a`
    from outside `outerFunction`, even after outerFunction has finished executing!
    In JavaScript, this function `innerFunction` is called a "closure".

    To cite the [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures):

    > Closures are functions that refer to independent (free) variables (variables
    > that are used locally, but defined in an enclosing scope). In other words,
    > these functions 'remember' the environment in which they were created.
    <!-- Break Here -->

    Although our outer function can only return one value,
    we’re not restricted to passing out a single function;
    rather, we can pass out a collection of functions
    (e.g. an object with methods).

    ```js
    var outerFunction = function(){
    var a = 100;
    return {
    increment: function() { a++; },
    print: function() { console.log(a); }
    };
    };
    var returnedObject = outerFunction();
    returnedObject.print(); // 100
    returnedObject.increment();
    returnedObject.print(); // 101
    ```

    Let’s rewrite the previous example as a factory for ‘Counter’ objects,
    using the ‘factory function’ pattern.

    A 'factory function' is a function you create that returns new objects
    each time that it is invoked it. Usually, these objects are pretty similar.
    However, a factory function is _distinct_ from a constructor, not least in that
    (a) there is no prototype which all objects share, and
    (b) there is no use of the `new` keyword

    ```js
    var counterFactory = function(){
    var count = 0;
    return {
    increment: function() { count++; },
    print: function() { console.log(count); }
    };
    };
    var counter = counterFactory(); // counterFactory returns a 'counter' object
    counter.print(); // 0
    counter.increment();
    counter.print(); // 1
    ```

    Closures are extremely useful in JavaScript because,
    by default, all properties on all objects are publicly available.
    This is not very ‘safe’ as a programming practice.
    Using closures allow us to ‘hide’ variables by making them only accessible
    by invoking the closure functions.

    One very common use case of closures is the IIFE
    (immediately invoked function expression):

    ```js
    var counter = (function(){ // same function as above!
    var count = 0;
    return {
    increment: function() { count++; },
    print: function() { console.log(count); }
    };
    })();
    counter.print(); // 0
    counter.increment();
    counter.print(); // 1
    ```

    In a way, you could say that an IIFE is a 'single-use factory function',
    since it is constructed in exactly the same way,
    but (because it is invoked immediately, and not stored in a variable),
    it cannot be invoked a second time.

    The only way to access the `count` variable is through the methods on `counter`.
    In effect, we have created an object with hidden properties and exposed methods.
    This is called the _JavaScript module pattern_, and it's the secret sauce that
    underlies all modern JS development frameworks, including Node.
  5. GA-MEB created this gist Jun 29, 2016.
    1 change: 1 addition & 0 deletions js-closures-teachback.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    ...