takeaway

  1. Understand var, let, const

scope

For the most part in javascript, there are only two scope types:

  • Global scope: A global scope is the outermost scope of a program and always exists.
  • Function scope: A function scope is created only when the function is defined, within the parent function scope/global scope.
/* Global scope starts */
var a = 1;

function func () { /* the func function scope starts */
  var a = 2;
  console.log(a);
}                  /* func function scope end */

func(); / / = > 2

console.log(a); / / = > 1
/* End of global scope */
Copy the code

The scope chain

// 1. Global scope
function foo(a) {
  // 2. scope of the foo function
  var b = a * 2;

  function bar(c) {
    // 3. Bar function scope
    console.log(a, b, c);
  }

  bar(b * 3);
}

foo(2); / / 2, 4 12
Copy the code

When a function accesses a variable, it looks in the local scope first. If it finds the target variable, it returns immediately. Otherwise, it looks in the parent scope. Go all the way to the global scope. We call this nesting mechanism of scopes “scope chain”

Application scenarios of the scope

One common use of scope is modularity, which deals with global scope contamination, variable name conflicts, bloated code structures and low reusability.

function module1 () {
  var a = 1;
  console.log(a);
}
function module2 () {
  var a = 2;
  console.log(a);
}
module1(); / / = > 1
module2(); / / = > 2
Copy the code

Module1 and module2 are two functions representing modules, and a variable with the same name is defined in the two functions. Due to the isolation nature of function scopes, the two variables are stored in different scopes (not nested). When executing these two functions, JS engine will read from different scopes. And the external scope does not have access to the a variable inside the function. In this way, the problems of global scope pollution and variable name conflict are solved ingeniously. And, because of the wrapping of the function, it looks much more encapsulated.

However, the function declarations above still look redundant and, more importantly, the function names for module1 and Module2 themselves pollute the global scope.

// Self-executing functions are modularized
// module1.js
(function () {
  var a = 1;
  console.log(a); / / 1}) ();// module2.js
(function () {
  var a = 2;
  console.log(a); / / 2}) ();Copy the code

In essence, self-executing functions solve the problems of naming conflicts and contaminating the global scope through function scope.

closure

To put it simply, a closure is a function defined inside a function that is returned and called externally, bypassing scope oversight and getting information about the function’s internal scope from outside the function itself.

function foo() {
  var a = 1;
  function bar() {
    console.log(a); / / 1
  }
  return bar;
}
var baz = foo();
baz(); // This forms a closure
Copy the code

We can briefly analyze the flow of the above code:

  1. At compile time, variables and functions are declared and scopes are determined.
  2. Run the functionfoo(), one will be createdfooThe execution context of the function is stored internallyfooAll variable function information declared in.
  3. functionfooAfter running, the internal function will bebarAssigns a reference to an external variablebazAt this time,bazThe pointer is pointing to orbarSo even though it’s locatedfooOutside of scope, it can still get itfooInternal variables of.
  4. bazBeing executed externally,bazInternal executable codeconsole.logRequest fetch from the scopeaVariable, local scope not found, continue request parent scope, foundfooIn theaVariable, return toconsole.logTo print out1.

Examples of closures

1. Accumulator:

  • Count is a global variable that can be manipulated anywhere else, and if count is reassigned or redefined anywhere else, the timer is broken.
var count = 0; 
function addCount() {
    count++;
}
document.body.addEventListener("click", addCount);
Copy the code
  • Use closures
function addCount() {
    var count = 0;
    var addCount = function() {
        count++;
   }
    return addCount;
}
document.body.addEventListener("click", addCount);
// Click once -> Output 1
// Click twice -> Output 2
Copy the code

2. Cache:

function eater () {
    let food = "apple";
    const obj = {
        eat: function () {
            if(food ! ="") {
                console.log("i am eating "+ food);
                food = "";
            } else {
                console.log("eat nothing"); }},push: function (myFood) { food = myFood; }};return obj;
};
const kevin = eater();
kevin.eat(); // i am eating apple
kevin.eat(); // eat nothing
kevin.push('banana');
kevin.eat(); // i am eating banana
Copy the code
function isFirstLoad () {
    const list = [];
    return function (option) {
        if(list.indexOf(option) >= 0) {
            // Check if it exists in the existing array
            console.log('pre-existing')}else {
            list.push(option);
            console.log('First incoming');
            // If no, return true and enter the data this time}}}var ifl = isFirstLoad();
ifl("kevin"); // First pass
ifl("leslie"); // First pass
ifl("kevin"); / / has been in existence
Copy the code

Considerations for using closures

Closures are a double-edged sword; they are generated when internal functions are saved externally. Closures cause the original scope chain not to be released, causing a memory leak (memory footprint)

Solution: can not use closure is not needed, timely release. fn = null; –> Make internal functions garbage objects –> reclaim closures

summary

I hope after reading this article you can have the following help:

  • Understand closures and make good use of them. Here’s another example (anti-vibration and throttling).
  • In-depth understanding of scopes and scope chains.

If there are any mistakes in this article, please correct them in the comments section. If this article has helped you, please like it and follow it.

Previous content recommended

  1. Deep copy
  2. Easily understand the JS prototype prototype chain
  3. New operator
  4. Handwritten bind/call/apply