JavaScript lexical scope and dynamic scope

Scope is the area of a program’s source code where variables are defined.

A scope specifies how to find a variable, that is, determine what access the currently executing code has to the variable.

Lexical scope is used, that is, static scope.

Static scope (lexical scope)

JavaScript uses lexical scope, so the scope of a function is determined at function definition time. Three types of scope in JS (global, function, block level)

  1. Global variables: variables declared outside a function (all variables that are not directly assigned by var are global variables)

  2. Local variables: variables declared inside a function (all variables that are not directly assigned by var are global variables)

Let’s take a closer look at an example to see the difference:

var value = 1;
function foo() {
  console.log(value);
}
function bar() {
  var value = 2;
  foo();
}
bar();
//????
Copy the code

We are using static scoping (lexical scoping) because we are using JS. Let’s examine the implementation:

The foo function first looks for value in its internal scope, and if so, uses the local variable. No, according to the written code it looks up one level, and that’s where we find that the value variable exists is 1;

From the little rhinoceros (Problem 2 I overturned the car)

var scope = "global scope";
function checkscope() {
  var scope = "local scope";
  function f() {
    return scope;
  }
  return f();
}
checkscope();
/ /??????

var scope = "global scope";
function checkscope() {
  var scope = "local scope";
  function f() {
    return scope;
  }
  return f;
}
checkscope()();
Copy the code

Return f; return f; return f; Checkscope === f; checkScope === f; checkScope == f

If you flip your car, you flip it three times

JavaScript uses lexical scope, so the scope of a function is determined at function definition time;

JavaScript uses lexical scope, so the scope of a function is determined at function definition time;

JavaScript uses lexical scope, so the scope of a function is determined at function definition time;

The answer is to quote the definitive JavaScript Guide

JavaScript functions are executed using the scope chain, which is created when the function is defined. The nested function f() is defined in the scope chain, where the variable scope must be a local variable. This binding remains in effect when f() is executed, no matter where or when f() is executed.

A diagram that says it all

Dynamic scope (JS does not use this compilation mode)

Languages that use dynamic scoping are Emacs Lisp, Common Lisp (both static scoping), and Perl (both static scoping). C/C++ macro used in the name of the dynamic scope.

Variables that are dynamically scoped are called dynamic variables.

Sketchy (1000 words)

The scope chain

This layer by layer relationship is the map of the scope chain.

You can think of it as a concentric circle structure, where each layer is assumed to be a function with variable objects associated with that layer of function; Assuming that the innermost function is executed, the scope chain can be thought of as a line in the diagram from the inside out, with the front end being itself and the end being the global execution environment. So what it does is, when you access a variable, it goes down the scope chain until you find it, and if you don’t find it in the outermost layer in the global execution environment, you get an error.

Normally, the value of a variable is in the scope of the function that created the variable, but if no value is found in the current scope, it is searched in the upper scope until it reaches the global scope. The chain of a search is called a scope chain.

var x = 10;
function fn() {
  console.log(x);
}
function show(f) {
  var x = 20;
  fn();
}
show(); / / 10
Copy the code

closure

Define the closure

Functions in JavaScript run in the scope in which they are defined, not the scope in which they are executed. The Butterfly Book


A function that has access to a variable in another function’s scope. The Little Red Book


Closures occur when a function can remember and access its lexical scope, even if the function is executing Little Dirty Books outside the current lexical scope.


Function objects can be associated by scope, and variables in the function body can be stored in the function scope, which is called a “closure” in the computer science literature. All javascirpt functions are closures.


All of the above books mention the following three points (special attention)

  • Execution environment: Each function has its own execution environment. When a function is executed, its environment is pushed into an environment stack. After the function is executed, the stack pops up its environment, returning control to the previous execution environment.

  • Variable object: Each execution environment has a variable object associated with it, and all variables and functions defined in the environment are stored in this object. When a function is executed, the variable object becomes an active object.

  • Scoped chain: A scoped chain of variable objects is created when code is executed in an environment. The purpose of scope chains is to ensure orderly access to all variables and functions that the execution environment has access to. At the front of the scope chain is always the variable object in the environment of the currently executing code. If the environment is a function, treat its active object as a variable object.

Take a chestnut

function a() {
  var text = "Hehe da";
  return function () {
    console.log(text);
  };
}
var b = a();
b();
Copy the code

When the a() function is executed, it returns an anonymous function whose scope chain has a reference to the live object property text of the execution environment of a(). The a() function is destroyed immediately after execution, but its variable object is still referenced by B, so its variable object is not disposed of by the garbage collection mechanism, but is kept in memory. This forms a closure. Finally, b() still reads the text variable defined by the destroyed function A.

For example, chestnut (classic)

function a() {
  var i = 0;
  return function () {
    console.log(i++);
  };
}
var b = a();
b(); / / 0
b(); / / 1
b(); / / 2
Copy the code

The role of closures

The advantage is that you can hide variables and then bridge the gap. Closures can indirectly manipulate the hidden variables. And keep the variable in memory without contaminating the global variable.

The downside is that it consumes memory, and if you don’t release this closure you’re going to keep using up memory. So how do you release it? Very simple, just like the function to assign null. (b = null)