preface

This 2771 word article takes about 8 minutes to read.

Summary: This article explains Javascript scopes, scope types, scope chains, and how Javascript sets up scope chains and finds variables.

  • Understanding Scope and Scope Chain in JavaScript
  • Public account: “front-end advanced learning”, reply to “666”, get a package of front-end technology books

A flower wither, not the whole barren spring.

The body of the

Scope and scope chains are fundamental concepts in Javascript and many other programming languages. Many Javascript developers don’t really understand them, but these concepts are essential to mastering Javascript.

Getting this concept right will help you write better, more efficient, and cleaner code, making you a better Javascript developer.

So, in this article, I’ll explain what scopes and scope chains are, and how Javascript engines manipulate and find variables internally.

Without delay, the text begins 🙂

What is scope

Scope in Javascript is about accessibility and visibility of variables. That is, what parts of the program have access to the variable, or where the variable is visible.

Why is scope important

  1. The most important aspect of the ** scope is security. ** variables can only be accessed within a specific area, and with scopes we can avoid accidentally making changes to a variable elsewhere in the program.
  2. The ** scope also reduces naming stress. ** We can define the same variable name under different scopes.

The type of scope

There are three types of scope in Javascript:

  1. Global scope;
  2. Function scope;
  3. Block-level scope;

1. Global scope

Any variables that are not declared in functions or braces are in global scope, and variables declared in global scope can be accessed anywhere in the program. Such as:

// Global variables
var greeting = 'Hello World! ';
function greet() {
  console.log(greeting);
}
// Prints 'Hello World! '
greet();
Copy the code

2. Function scope

A function scope is also called a local scope, so if a variable is declared inside a function it goes under a function scope. These variables can only be accessed inside the function, not outside it. Such as:

function greet() {
  var greeting = 'Hello World! ';
  console.log(greeting);
}
// Prints 'Hello World! '
greet();
// Uncaught ReferenceError: greeting is not defined
console.log(greeting);
Copy the code

3. Block level scope

ES6 introduces the let and const keywords. Unlike the var keyword, variables declared using let and const in braces exist in block-level scope. These variables cannot be accessed outside of braces. See the examples:

{
  // block level scope variable
  let greeting = 'Hello World! ';
  var lang = 'English';
  console.log(greeting); // Prints 'Hello World! '
}
/ / variable 'English'
console.log(lang);
// Uncaught ReferenceError: greeting is not defined
console.log(greeting);
Copy the code

As you can see from the above code, the variable lang declared with var inside curly braces is accessible outside of curly braces. Variables declared using VAR do not have block-level scope.

Scope nesting

Just as functions in Javascript can declare functions within one function, scopes can be nested within another scope. Take an example:

var name = 'Peter';
function greet() {
  var greeting = 'Hello';
  {
    let lang = 'English';
    console.log(`${lang}: ${greeting} ${name}`);
  }
}
greet();
Copy the code

There are three levels of scope nesting. The first layer is a block-level scope (declared by let) nested in the greet function. The outer scope is the global scope.

Lexical scope

Lexical scope (also known as static scope) literally means that the scope is determined at the lexical stage (usually the compile stage) rather than at the execution stage. See the examples:

let number = 42;
function printNumber() {
  console.log(number);
}
function log() {
  let number = 54;
  printNumber();
}
// Prints 42
log();
Copy the code

As you can see from the code above, wherever printNumber() calls console.log(number), it prints 42. Dynamic scoping is different, and what console.log(number) prints depends on where printNumber() is called.

For dynamic scopes, the console.log(number) line above prints 54.

With lexical scoping, we can determine the scope of a variable just by looking at the source code, but with dynamic scoping, we can’t determine the scope of a variable until the code executes.

Most programming languages like C, C++, Java, Javascript, and so on support static scopes. Perl supports both dynamic and static scopes.

The scope chain

When a variable is used in Javascript, the Javascript engine first tries to look for it in the current scope, if not, in its upper scope, and so on until it finds the variable or reaches the global scope.

If the variable is still not found in the global scope, it either implicitly declares the variable in the global scope (in non-strict mode) or reports an error directly.

Such as:

let foo = 'foo';
function bar() {
  let baz = 'baz';
  / / print 'baz'
  console.log(baz);
  / / print 'foo'
  console.log(foo);
  number = 42;
  console.log(number);  / / print 42
}
bar();
Copy the code

When the function bar() is called, the Javascript engine first looks for the variable baz in the current scope, then looks for the variable foo but finds none in the current scope, and then continues to look for it in the outer scope (in this case found in the global scope).

We then assign 42 to the variable number. The Javascript engine looks for the number variable step by step in the current scope as well as in the external scope (it doesn’t find it).

In non-strict mode, the engine creates a global variable of number and assigns 42 to it. But if you’re in strict mode you’ll get an error.

** Conclusion: ** When using a variable, the Javascript engine will work its way up the scope chain until it finds the variable.

How do scopes and scope chains work

Now that we’ve covered scopes and the types of scopes, let’s take a look at how the Javascript engine determines the scope chain of variables and how to find them.

To understand how Javascript does variable lookups, you must understand the concept of lexical context in Javascript (see: Understanding execution Context and execution stack in Javascript).

What is lexical context

A lexical environment is a structure of identity-variable mappings (identifiers are the names of variables/functions, and variables are references to actual objects [objects containing functions and array types] or underlying data types).

Simply put, the lexical environment is where the Javascript engine stores references to variables and objects.

Note: Do not confuse the lexical context, which is defined at code compilation time, with the lexical scope, which is where the Javascript engine stores references to variables and objects.

A lexical environment might look like this:

lexicalEnvironment = {
  a: 25.obj: <ref. to the object>
}
Copy the code

Only when the code for that scope is executed does the engine create a new lexical environment for that scope. The lexical environment also records the external lexical environment (that is, the external scope) referenced. Ex. :

lexicalEnvironment = {
  a: 25.obj: <ref. to the object>
  outer: <outer lexical environemt>
}
Copy the code

How do Javascript engines do variable lookups

Now that we know the concepts of scope, scope chains, and lexical environments, let’s take a look at how Javascript engines use lexical environments to determine scope and scope chains.

Use examples to understand the above concepts:

let greeting = 'Hello';
function greet() {
  let name = 'Peter';
  console.log(`${greeting} ${name}`); // Hello Peter
}
greet();
{
  let greeting = 'Hello World! '
  console.log(greeting); // Hello World!
}
Copy the code

When the above code loads, it first creates a global lexical environment containing variables and functions declared globally. Something like this:

globalLexicalEnvironment = {
  greeting: 'Hello'
  greet: <ref. to greet function>
  outer: <null>
}
Copy the code

The outer field here is set to NULL because the global lexical environment is already the top-level lexical environment.

We then call greet() and a new lexical environment is created:

functionLexicalEnvironment = {
  name: 'Peter'
  outer: <globalLexicalEnvironment>
}
Copy the code

The outer field here is set to globalLexicalEnvironment because its outer scope is the global scope.

Log (‘ ${greeting} ${name} ‘). The Javascript engine first looks for the variables greeting and name in the lexical environment of the current function, but only name is found, not greeting. Then continue looking for greeting in the upper lexical environment (global lexical environment in this case). Finally, we found Greeting in the global lexical environment.

Then execute the bracketed code to create a new lexical environment for the block level. As follows:

blockLexicalEnvironment = {
  greeting: 'Hello World'.outer: <globalLexicalEnvironment>
}
Copy the code

Then execute the console.log(greeting) line, first looking for greeting, OK, find, and end in the lexical environment of this layer. The variable is no longer searched for in the outer scope (in this case, the global scope).

** Note: ** Only let and const declarations create a new lexical store. Variables declared using var are stored in the same lexical environment as the current block (curly braces) (global or functional lexical).

** When a variable is used, the Javascript engine first looks for it in the current lexical context, and if it can’t find it in the upper lexical context, until it finds it.

conclusion

A scope is a region that a variable can access and see. Like functions, Javascript scopes can be nested, and the Javascript engine iterates through the scope to find the variable to use.

Javascript uses lexical scope, which means that the role of a variable is determined at compile time.

The Javascript engine uses a lexical environment to store variables and functions during program execution.

Scopes and scope chains are fundamental concepts in Javascript, and understanding scopes and scope chains can make you a better Javascript developer.

The above.


The ability is limited, the level is general, welcome to erratum, greatly appreciated.

To subscribe for more articles, follow the public account “Front-end Advanced Learning” and reply to “666” for a package of front-end technology books