Closures and immediate function applications

A closure

Closures have been defined and explained in this article, including how to implement a closure. For details, see the previous section.

The core role of closures is to privatize variables and prevent external access.

Execute the function immediately

The immediate execution Function is IIFE (Immediately-Invoked Function Expressions).

As the name implies, it is executed as soon as it is defined. The special feature of an immediate function is that it takes no life and executes immediately when it is defined. It is immediately destroyed after execution and does not occupy memory.

Closure and immediate function applications

Let’s talk about the use of immediate functions, how they work with closures, and what they can achieve.

1. Scenario 1

Count for a variable number, every one second +1, and print the number

Under normal circumstances, we might write something like this:

var number = 0 setInterval(function () { console.log(++number) // 1 2 3 4 5 6 7 8 9 10 ... }, 1000).Copy the code

This is fine, but when number is exposed globally, we can “hide” number as a temporary variable by executing the function immediately.

setInterval((function () {
    var number = 0
    return function () {
            console.log(++number) // 1 2 3 4 5 6 7 8 9 10 ...
    }
})(), 1000)
Copy the code

If you look closely at this part of the code, the function he’s actually executing in the timer is still

The function in parentheses is passed to the timer in the form of a return from the immediately executing function. In this way, number is wrapped inside the timer by the immediate function and is not accessible outside the timer.

2. Scenario 2

Construct a function that returns an array whose ith element is a function that prints I.

function getLogsArray () {
    var arr = []
    for (var i = 0 ; i < 100 ; i++) {
        arr[i] = function () {
            console.log(i)
        }
    }
    return arr
}

const logger = getLogsArray()
logger[1]() // 100
logger[2]() // 100
logger[50]() // 100
Copy the code

This is clearly the wrong result and not the desired result

Logger [1]() should print 1 instead of 100

The cause of this result must be the scope of the problem, in fact we found that the recycling of the I through var to declare, so the scope of the I got a raise, I called the entire function scope under the only variable values, i.e. array inside all I point to the current scope an I, when the loop execution after, I becomes 100, so whatever element in the entire array is going to print 100.

How to solve this problem? The easiest way to do this is to change the var keyword to the let keyword, so that the scope of I only exists in the loop, and each loop is a new variable, so that the I printed in the array is different.

function getLogsArray () {
    var arr = []
    for (let i = 0 ; i < 100 ; i++) { // cahnge var to let
        arr[i] = function () {
            console.log(i)
        }
    }
    return arr
}

const logger = getLogsArray()
logger[1]() // 1
logger[2]() // 2
logger[50]() // 50
Copy the code

Another solution, which is the focus of the moment, is to use immediate execution functions.

function getLogArray () {
    var arr = []
    for (var index = 0 ; index < 10; index++) {
        (function (i) {
            arr[i] = function () {
                console.log(i)
            }
        })(index)
    }
    return arr
}

const loggerArray = getLogArray()
loggerArray[1]() // 1
loggerArray[2]() // 2
loggerArray[50]() // 50
Copy the code

In the function, the value of I is changed, but we can set the print method to a separate scope by taking an argument from the immediate-execute function and accepting the index parameter. In the print method, I is the independent argument in the immediate-execute function. No matter how index is edged, it does not affect printing.

Four:

Executing functions immediately does not end up creating and saving new variables, and working with closures can create separate scopes for closures.