Scope and closure details

preface

Interview Questions:

Knowledge points involved:

  • Execution context

  • this

  • scope

  • The scope chain

  • closure

Execution context

There are two main cases of execution context:

  • Global code: A

  • Function code: Each function has a context. Things to do are: variable definition, function declaration, this, arguments

PS: Note the difference between “function declaration” and “function expression”.

Global execution context

Identify the window as a global execution context before executing global code.

(1) preprocess global data :(no assignment is made)

  • The global variable defined by var ==>undefined is added as the property of window

  • Function declared global function ==> assignment (fun), added as window method

  • This = = > assignment (Windows)

(2) Start executing global code

Function execution context

Before the function is called and ready to execute the function body, the corresponding function execution context object (virtual, existing on the stack) is created.

(1) Pretreatment of local data:

  • Parameter ==> Assignment (argument)==> added as an attribute of the execution context

  • Arguments ==> Assign (argument list) to add as an attribute for the execution context

  • The local variable defined by var ==>undefined is added as an attribute of the execution context

  • Function declared function ==> assignment (fun), added as an execution context method

  • This ==> Assignment (the object calling the function)

(2) Start executing the function body code

Execution context stack

  • 1. Before global code execution, the JS engine creates a stack to store and manage all execution context objects

  • 2. After the global execution context (window) is determined, add it to the stack (push)

  • 3. After the function execution context is created, add it to the stack (pushdown)

  • 4. After the current function completes, remove the object at the top of the stack (unstack)

  • 5. When all the code has been executed, only Windows is left on the stack

this

This refers to the object on which the function is called. This always refers to the object on which the function is run.

Each time a function is called, the parser passes an implicit argument inside the function. The implicit argument is this.

This refers to different objects depending on how the function is called:

  • 1. When called as a function, this is always window. Such as fun (); Equivalent to the window. The fun ();

  • 2. When called as a method, this is the object on which the method is called

  • 3. When called as a constructor, this is the newly created object

  • 4. When called with call and apply, this is the specified object

It is important to note that the reference of this is not confirmed at function definition, but only at function execution.

Several scenarios of this:

  • Execute as a constructor

Such as:

    function Foo(name) {
        //this = {};
        this.name = name;
        //return this;
    }

    var foo = new Foo();
Copy the code
  • 2. Execute as a property of the object
    var obj = {
        name: 'A'.printName: function () {
            console.log(this.name);
        }
    }

    obj.printName();

Copy the code
  • 3. Execute as a normal function
    function fn() {
        console.log(this); //this === window
    }

    fn();
Copy the code
  • 4, Call apply bind

scope

Scope refers to the scope of a variable. It is static (as opposed to a context object) and is determined at code writing time.

Effect: Isolate variable, different scope under the same name variable will not conflict.

Classification of scopes:

  • Global scope

  • Function scope

  • No block scope (ES6 has it)

if (true) {
    var name = 'smyhvae';
}
console.log(name);
Copy the code

In the above code, no error is reported because: Name is a global variable, although it is defined in the block.

Global scope

JS code written directly in script tags is in global scope.

In global scope:

  • In the global scope, there is a global object called Window, which represents a browser window that is created by the browser and can be used directly.

  • Variables created are stored as properties of the Window object.

  • Functions created are stored as methods of the Window object.

Variables in the global scope are global variables and can be accessed in any part of the page.

Variable declaration ahead of time :(variable promotion)

Variables declared with the var keyword (e.g., var a = 1) will be declared (but not assigned) before all code is executed, but if the variable is not declared with the var keyword (e.g., a = 1), the variable will not be declared earlier.

Example 1:

    console.log(a);
    var a = 123;
Copy the code

Print result: undefined

Example 2:

    console.log(a);
    a = 123;   // a is the same as window.a
Copy the code

The program will report an error:

Function declaration ahead of time:

  • useFunction declarationFunction created in the form offunction foo(){}.Will be declared in advance.

That is, it is created before all the code is executed, so we can call the function before it is declared.

  • useFunctional expressionCreated functionvar foo = function(){}.Will not be declared in advance, so it cannot be called before declaration.

It makes sense because foo is declared and undefined, and function(){} is not assigned to it.

So, in the following example, an error will be reported:

Function scope

The function scope is created when the function is called and destroyed when the function is finished executing.

A new function scope is created each time a function is called, and they are independent of each other.

Variables in the function scope are accessible in the global scope. Variables in the function scope are not accessible in the global scope.

To access global variables in a function, use the window object. (For example, both the global scope and the function scope define variable A. If you want to access the global variable, use window.a.)

Reminder 1:

There is also a pre-declaration feature in function scope:

  • Variables declared with the var keyword are valid within the scope of the function and are declared before all code in the function executes

  • Function declarations are also executed before all code in a function is executed

Therefore, variables that are not declared by var in functions become global variables and are not declared in advance.

Example 1:

        var a = 1;

        function foo() {
            console.log(a);
            a = 2;     // a is equivalent to window.a
        }

        foo();
        console.log(a);   // Print 2

Copy the code

In the code above, foo() prints 1. If the first line of code is removed, Uncaught ReferenceError: A is not defined is printed

Note 2: defining parameters is equivalent to declaring variables in function scope.

function fun6(e) { console.log(e); } fun6(); // Undefined fun6(123); // Prints 123Copy the code

The difference between scope and execution context

The difference between 1:

  • Outside of global scope, each function creates its own scope, which is defined when the function is defined. Not when the function is called

  • The global execution context is created after the global scope is determined and immediately before the JS code executes

  • A function execution context is created when a function is called and before the function body code executes

The difference between 2:

  • The scope is static, existing as long as the function is defined and does not change

  • The execution context is dynamic, created when a function is called and released automatically when the function call ends

Contact:

  • The execution context (object) is subordinate to its scope

  • Global context ==> Global scope

  • Function context ==> Corresponding function usage field

The scope chain

When operating on a variable in function scope, it looks in its scope first and uses it directly if it has one (the proximity rule). If not, look up the scope until the global scope is found; If the global scope is still not found, ReferenceError is reported.

Variables defined by external functions can be used by internal functions, but not vice versa.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
        // Create scope as long as it is a function
        // create a function in the function
        // Scope inside function can access scope outside function
        // If multiple functions are nested, then a chain access structure is formed, which is called the scope chain

        / / f1 - > global
        function f1(){
            / / f2 -- -- -- -- -- -- > > f1 globally
            function f2(){
                / / f3 -- - > f2 -- -- -- -- -- -- > > f1 globally
                function f3(){}/ / f4 - > f2 -- -- -- -- -- -- -- > > f1 globally
                function f4(){}}/ / f5 -- -- -- -- -- -- -- > > f1 globally
            function f5(){}}</script>
</head>
<body>

</body>
</html>
Copy the code

To understand:

  • A chain of scopes of multiple subordinate relationships that are oriented from bottom up (inside out)

  • Variables are found along the scope chain

Rules for finding a variable:

    var a = 1

    function fn1() {
      var b = 2

      function fn2() {
        var c = 3
        console.log(c)
        console.log(b)
        console.log(a)
        console.log(d)
      }
      fn2()
    }
    fn1()
Copy the code
  • Finds the corresponding property in the execution context of the current scope, if any, and otherwise goes to 2

  • Find the corresponding attribute in the execution context of the upper scope, return it directly if any, otherwise go to 3

  • Do the same for 2 again, up to the global scope, and throw an exception if not found

closure

Closures are functions that can read data (variables/functions) inside other functions.

Local variables can be read only by subfunctions inside a function, so closures can be understood simply as “functions defined inside a function”.

The above two sentences, ruan Yifeng’s article, you may not understand, look at the following explanation and examples.

How do YOU generate closures

Closures occur when a nested inner (child) function references a variable or function of the nested outer (parent) function.

What exactly is a closure?

Use Chrome debug to view

  • Understanding 1: Closures are nested internal functions (most people)

  • Understanding two: The object that contains the variable or function being referenced (very few people)

Note: Closures exist in nested inner functions.

Conditions that generate closures

  • 1. Function nesting

  • 2. The inner function references the data (variable/function) of the outer function.

Let’s look at condition 2:

    function fn1() {
        function fn2() {}return fn2;
    }

    fn1();
Copy the code

The above code does not produce a closure because the inner function fn2 does not reference the variables of the outer function fn1.

PS: Another condition is that an external function is called and an internal function is declared. Such as:

    function fn1() {
        var a = 2
        var b = 'abc'

        function fn2() { // If the fn2 inner function is declared ahead of time, the closure is generated (without calling the inner function).
            console.log(a)
        }

    }

    fn1();

    function fn3() {
        var a = 3
        var fun4 = function () {  //fun4 uses functions created by "function expressions", where internal functions are not declared in advance
            console.log(a)
        }
    }

    fn3();

Copy the code

Common closures

    1. Take one function as the return value of another function
    1. Pass a function as an argument to another function call.

Closure 1: Takes one function as the return value of another function

    function fn1() {
      var a = 2

      function fn2() {
        a++
        console.log(a)
      }
      return fn2
    }

    var f = fn1();   // Execute the external function fn1 and return the internal function fn2
    f() // 3 // Run fn2
    f() // 4 // Run fn2 again

Copy the code

When f() is executed the second time, a is incremented, indicating that the data in the closure is not lost, but stored in memory. Without the closure, the variable A disappears after the third to last line of code execution.

In the above code, only one closure object is created, although the inner function is called twice.

That is, to see that a closure object is created, look at how many times the outer function is executed (regardless of how many times the inner function is executed).

Closure 2. Pass the function as an argument to another function call

    function showDelay(msg, time) {
      setTimeout(function() {  // This function is a closure because it is a nested subfunction and refers to the external function variable MSG
        alert(msg)
      }, time)
    }
    showDelay('atguigu'.2000)
Copy the code

In the above code, the closure is the inside funciton, because it is a nested subfunction and refers to the external function’s variable MSG.

The role of closures

  • 1. Use variables inside a function to live in memory after the function is executed (extends the lifetime of local variables)

  • 2. Make it possible to manipulate (read and write) data (variables/functions) from outside the function.

Let’s take this code and analyze it:

    function fn1() {
      var a = 2

      function fn2() {
        a++
        console.log(a)
      }
      return fn2;
    }

    var f = fn1();   // Execute the external function fn1 and return the internal function fn2
    f() // 3 // Run fn2
    f() // 4 // Run fn2 again

Copy the code

Function 1 Analysis:

In the code above, after the external function fn1 is executed, variable A does not disappear immediately, but is saved in memory.

Function 2 Analysis:

The variable a in fn1 is in the scope of fn1 and therefore cannot be accessed externally. But with closures, you can externally manipulate variable A.

The result is that the variable A is invisible, but can be manipulated.

For example, the effect achieved above is: I can’t see the variable A, but each time I execute the function, I increment a by 1. Of course, if I really want to see a, I can just return a in Fn2.

Answer a few questions:

  • Question 1. After the function is executed, does the local variable declared inside the function still exist?

Answer: Usually no, only variables that exist in closures can exist.

The fundamental reason that closures persist is f, because F receives Fn1 (), which is a closure, and the closure has a in it. Notice that at this point, fn2 does not exist, but the object inside it (the closure) still exists because it was received with F.

  • Question 2. Can local variables inside a function be accessed directly from outside the function?

No, but we can let the outside manipulate it through closures.

The life cycle of closures

  1. Generated: generated when the nested inner function fn2 is declared (not called)

  2. Death: When nested internal functions become garbage objects. (For example, if f = null, you can make f garbage. F no longer refers to the closure object.

Closure applications: Define JS modules with specific functions

  • Encapsulate all data and functionality within a function (private), exposing only one object or function containing n methods.

  • The user of the module only needs to invoke the method of the object exposed by the module to realize the corresponding function.

Methods a

(1) mymodule.js :(defines a module to expose multiple functions for external calls)

function myModule() {
    // Private data
    var msg = 'Smyhvae Haha'

    // A function that operates on private data
    function doSomething() {
        console.log('doSomething() ' + msg.toUpperCase()); // The string is uppercase
    }

    function doOtherthing() {
        console.log('doOtherthing() ' + msg.toLowerCase()) // The string is lowercase
    }

    // Expose multiple functions by wrapping them in object literals
    return {
        doSomething1: doSomething,
        doOtherthing2: doOtherthing
    }
}
Copy the code

In the code above, the data inside can be manipulated by doSomething1 and doOtherthing2 without being visible to the outside world.

(2) index. HTML:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Application of 05_ closure _ Custom JS module</title>
</head>
<body>
<! Closure application: Define JS module * JS files with specific functions * encapsulate all data and functions within a function (private) * 【 important 】 only expose an object or function containing n methods * module users, only need to use the object exposed by the module to call the method to achieve the corresponding function -->
<script type="text/javascript" src="myModule.js"></script>
<script type="text/javascript">
    var module = myModule();
    module.doSomething1();
    module.doOtherthing2();
</script>
</body>
</html>
Copy the code

Way 2

The same is the implementation of one way of function, here we take another way.

Mymodule2.js :(is an anonymous function that executes immediately)

(function () {
    // Private data
    var msg = 'Smyhvae Haha'

    // A function that operates on private data
    function doSomething() {
        console.log('doSomething() ' + msg.toUpperCase())
    }

    function doOtherthing() {
        console.log('doOtherthing() ' + msg.toLowerCase())
    }

    // An external function is an anonymous function even though it is running. We can pass both methods directly to the window object
    window.myModule = {
        doSomething1: doSomething,
        doOtherthing2: doOtherthing
    }
})()
Copy the code

(2) index.html:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Application of 05_ closure _ Custom JS module 2</title>
</head>
<body>
<! - the application of the closure 2: define JS module * * JS files with specific functions will all data and functions are encapsulated within a function (private) * only to expose a bag * n method of the object or function module users, only need to pass the module exposed call methods to realize the corresponding function -- -- >

<! Import myModule file -->
<script type="text/javascript" src="myModule2.js"></script>
<script type="text/javascript">
    myModule.doSomething1()
    myModule.doOtherthing2()
</script>
</body>
</html>

Copy the code

In the two files above, we pass the two methods directly to the window object in mymodule2.js. As a result, when the js file is introduced in index.html, the anonymous functions in it are executed immediately. Use myModule directly in index.html.

Conclusion:

Of course, after comparing method 1 with method 2, we prefer method 2 because it is very convenient.

However, both approaches use closures.

Disadvantages of closures and solutions

Disadvantages: After the function is executed, local variables in the function are not released, occupying the memory for a long time and causing memory leaks.

Solution: can not use closure is not needed, timely release. Such as:

    f = null;  // make internal functions garbage objects --> recycle closures
Copy the code

In a word, you need it, is the advantage; You don’t need it, it’s a weakness.

Memory overflow and memory leak

Out of memory

Memory overflow: an error in the execution of a program. An out-of-memory error is thrown when the program runs on more memory than is available.

Code examples:

    var obj = {};
    for (var i = 0; i < 10000; i++) {
    obj[i] = new Array(10000000);  // All the contents of the array are stored in obj, so obJ takes up a lot of memory
    console.log("-- -- -- -- --");
    }
Copy the code

A memory leak

Memory leak: Occupied memory is not released in time.

Note that the accumulation of memory leaks can easily lead to memory overflow.

Common memory leaks:

  • 1. Unexpected global variables

  • 2. Timers or callbacks that don’t clean up in time

  • 3. The closure

Case 1:

    // Unexpected global variables
    function fn() {
        a = new Array(10000000);
        console.log(a);
    }

    fn();
Copy the code

Case 2:

    // There is no timer or callback to clean up in time
    var intervalId = setInterval(function () { // Do not clean up after starting the cycle timer
        console.log(The '-')},1000)

    // clearInterval(intervalId); // Clean up timer
Copy the code

Case 3:

<script type="text/javascript">
  function fn1() {
    var a = 4;
    function fn2() {
      console.log(++a)
    }
    return fn2
  }
  var f = fn1()
  f()

  // f = null // make internal functions garbage objects --> reclaim closure
</script>
Copy the code

My official account

Want to learn skills beyond code? Might as well pay attention to my wechat public number: front-end Ozawa

Scan and you will discover another whole new world, and it will be a beautiful accident:

More wonderful articles please pay attention to the blogger, will be published one by one,