Anonymous functions, immediate execution functions and closures in JavaScript

Posted by Mortier on Tue, 14 Apr 2020 12:09:10 +0200

Anonymous functions have no function name and cannot be used alone;

Immediate execution function is implemented based on anonymous function, and there is no function name. It will be executed immediately after definition;

A closure is a function that has access to variables in the scope of another function. Anonymous functions and immediate execution functions become closures as long as they satisfy the condition that they have access to variables in the scope of another function.

Anonymous function

Anonymous function: function without function name

Anonymous functions cannot be defined and used separately

function foo() {
  console.log('Ordinary function');
}
// Remove function name foo 
function () { // SyntaxError: Function statements require a function name
  console.log('Anonymous function');
}
Application scenario of anonymous function
  • For function expressions
  • As return value
  • Used to define object methods
  • As a callback function
  • For immediate function execution
  • For DOM element registration events
  • Other...

For function expressions

var sum = function (num1, num2) {
  return num1 + num2;
};
console.log(sum(2, 3)); 

As return value

function sum(sum1, sum2) { 

  return function() {
    return sum1 + sum2;    
  }

}
console.log(sum(2, 3));    // [Function]
console.log(sum(2, 3)());  // 5

Used to define object methods

var obj = {
  name: 'uakora',
  age: 27,
  foo: function() {
    console.log(this.name + ' ' + this.age);
  }
};
obj.foo(); // uakora 27 

As a callback function

setTimeout(function() {
  console.log('Anonymous function as callback function');
}, 1000);

For immediate function execution

(function() {
  console.log('Immediate execution functions are created based on anonymous functions');
}());

For DOM element registration events

<input type="button" value="Click me!" id="btn">
<script>
    var btn = document.querySelector("#btn");
    //Register click event for button
    sub.onclick = function(){
        console.log('Click event');
    }
</script>

Execute function now

IIFE (immediately invoked function expression) is a function that will be executed immediately after it is defined. Its essence is a syntax.

Form of immediate execution function

Two common forms

Common form 1: wrap anonymous functions in a bracket operator followed by a bracket

(function () {
  console.log('Execute function now');
})(); // !! Special note: if this immediate function is immediately followed by another immediate function, be sure to add a semicolon at the end, otherwise the immediate function will report an error!

// If the last immediate function is executed without semicolon, the following code will report an error: TypeError: (intermediate value)(...) is not a function
(function (a, b, c) { // Formal parameter
  console.log(a + b + c);  // 6
})(1, 2, 3); // Real reference

Common form 2: anonymous function is followed by a bracket, and then the whole function is wrapped in a bracket operator

(function () {
  console.log('Execute function now');
}());

(function (a, b, c) { // Formal parameter
  console.log(a + b + c);  // 6
}(1, 2, 3)); // Real reference

Other forms

You can replace the first bracket in common form 1 with the operators!, +, -, ~

!function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

+function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

-function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);

~function (a, b, c) { 
  console.log(a + b + c);  // 6
}(1, 2, 3);
The function of immediate execution

The most essential function of immediate execution is to create a separate scope. With this function, you can

  • Initialize data and pages (only once)
  • In modular development, define private variables to prevent global pollution (independent scope)
  • Solve the problem of state saving in closures; (a common problem is that a function returns multiple functions, calls these functions, and prints the internal variables of the parent function)

case analysis

var liList = document.getElementsByTagName('li');
for(var i = 0; i < liList.length; i++) {
  liList[i].onclick = function() {
    alert(i); // Result: the alert always comes out with 6 instead of 0, 1, 2, 3, 4, 5
  }
}

Expected results: 0, 1, 2, 3, 4, 5
Actual result: alert always comes out with 6
Cause analysis: there is no independent scope. Each click of the execution function accesses the same i value (and the value 6 after the end of the cycle)
Solution: use the execute now function to create a separate scope for each li element's click event function

var liList = document.getElementsByTagName('li');
for (var i = 0; i < 6; i++) {
  (function (i) {
    liList[i].onclick = function () {
      alert(i); // 0,1,2,3,4,5
    }
  })(i);
}

closure

A     closure is a function that has access to variables in the scope of another function. A common way to create a closure is to create another function within one function. Closures can have function names, or they can be anonymous (no function names);

Closure form 1: directly in the form of anonymous function as the return value of external function (general usage)

function outer() {
  var n = 1;

  return function() {
    n++; // Access the variable n in the scope of outer function to form a closure
    console.log(n);
  }
}

outer()();

Closure form 2: define an internal function within an external function and return the internal function name

function outer() {
  var n = 1;

  function inner() {
    n++; // Access the variable n in the scope of outer function to form a closure
    console.log(n);
  }

  return inner;
}

outer()();

Closure form 3: define an immediate execution function within an external function

function outer() {
  var n = 1;

  (function() {
    n++; // Access the variable n in the scope of outer function to form a closure
    console.log(n);
  })();

}

outer();
The function of closure

Function 1: you can directly access variables in the function scope
Function 2: the variables in the function scope can always be saved in memory as global variables (in fact, whether local variables can always be saved depends on the execution form of the closure)

Explanation: the analysis of role two is personal understanding

The following example is to prove the point: whether a closure can keep local variables all the time depends on the execution form of the closure

Closure execution method 1: immediately execute a () after the returned closure

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

outer()();  // 2
outer()();  // 2  

Closure execution method 2: assign the returned closure to a global variable, and the global variable runs () operation to execute the closure

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

var inner = outer();
inner();    // 2
inner();    // 3 (based on 2 plus 1)

The above two execution methods can only be used separately to illustrate the second execution method, which can make the closure keep local variables all the time, but it can not be proved that the first execution method of the closure can not keep local variables all the time, because each time the outer() function is executed, the variable n is reinitialized.

Continue to look at the following code, using both methods of closure execution:

function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log(n);
  }

  return inner;
}

var inner = outer();

outer()();  // 2
outer()();  // 2  (Flag1)

inner();    // 2  (Flag2)
inner();    // 3

As you can see, the values of Flag1 and Flag2 are both 2. Assuming that the closure execution mode such as outer()() will always save local variables in memory, the value at Flag2 should be 3.

Obviously, the assumption is not true.

So it shows that a closure is not always able to save local variables in memory, but also related to the execution mode.

Actively freeing memory
function outer() {
  var n = 1;

  function inner() {
    n++;
    console.log('n = ', n);
  }

  return inner;
}

var inner = outer();
inner();    // 2  
inner();    // 3

inner = null;  // Dereference a closure to free memory
Application scenarios of closures
  • Protecting the safety of local variable of function
  • Maintain a variable in memory
  • Implement JS private properties and private methods by protecting the security of variables (cannot be accessed externally)

Notes on using closures

   because a closure carries the scope of the function that contains it, it consumes more memory than other functions. Overuse of closures can cause excessive memory usage

Topics: Javascript