“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022”

What is the scope

A scope is almost a basic function that can be used to store variables that can be accessed or modified later.

Let’s take a simple chestnut 🌰 to facilitate understanding:

var nubility = 'Hello Varlet! '
Copy the code

Let’s parse what the browser does when it gets this string of code

  • The compiler looks to see if a Nubility already exists in the scope. If so, the compiler ignores the var declaration and continues compiling; Otherwise, the scope will be required to declare a variable nubility

  • Nubility = ‘Hello Varlet! The code for the assignment operation is handed to the engine

  • The engine will first ask if nubility exists in the scope when it gets the code. If so, the engine uses the variable, otherwise it continues to look up the variable in the next level of scope

  • If nubility is found in scope, then ‘Hello Varlet! ‘or the engine will throw an exception

VM418:1 Uncaught ReferenceError: nubility is not defined
Copy the code

Lexical scope

Let’s start with the origin of the name lexical scope.

The compiler takes the source code we’ve written and lexicalizes it, checking for characters in the source code and assigning semantics to words if it’s stateful parsing. (also known as static scope)

In a word: lexical scope is the scope of a definition at the lexical stage.

Semantization is determined by where our variables and block-level scopes are written when we write code.

An 🌰

  • The yellow box contains the global and has only one identifier, A

  • The blue box is the scope created by A and contains three identifiers, name, B, and Author

  • The red part contains the scope created by B, which has only one SCORE identifier

From here, we can see that the corresponding boxes are determined by the edge writing of their scoped block code, and are contained level by level.

The structure of scopes and their positional relationships with each other can provide the engine with positional information for finding identifiers.

Let’s parse the above code

  • The engine looks for references to author,name, and score when console.log(author,name,score) is executed

  • The engine cannot find author and name in scope B, so it will continue the search in scope A

  • In scope A, the engine finds author and name and uses this reference

To summarize: scoped lookup stops when the first matching identifier is found

In a multilevel nested scope, you can define identifiers with the same name, and the look-up of the scope looks outward from the innermost layer where the runtime resides until the first matching identifier is found.

⚠ ️ ⚠ ️ ⚠ ️ ⚠ ️ ⚠ ️ ⚠ ️

In fact, this is not absolute

😳😳😳 Damn it! Let’s take a break

Ok, the time is over at 😋. Next we talk about deception morphology

There are two mechanisms in JS that can modify the lexical scope at run time: eval and with. There is a general consensus in the community that this mechanism can lead to performance degradation, so we won’t go into that too much, and we’ll just use Eval as an example.

Let’s start with eval: You can take a string as an argument and treat its contents as code written in that part of the program.

An 🌰 :

function a(str){
  eval(str)
  console.log(num)
}
var num = 1

a('var num = 2')
Copy the code

Var num = 2 in an eval call is treated as if it were in a’s scope. The lexical scope of A has been modified to mask the external variable with the same name num, so that the engine will only find num inside A when it executes console.log.

Function scope

The scope of a function is that all variables belonging to the function can be used and reused (including nested subscopes) within the scope of the function.

In software design, we follow the principle of minimum exposure. That is, we can use embedded scopes to privatize variables and functions without contaminating the whole world.

An 🌰

function a(num){
  b = num + c(num)
  console.log(b)
}

var b

function c(num){
  return 2*num
}

a(2)
Copy the code

In this case, both b and c should be private parts of the implementation of a’s specific operations, and can be modified in unintended or intentional ways globally, so it makes more sense to hide b and C inside a.

function a(num){
  var b

  function c(num){
    return 2*num
  }

  b = num + c(num)
  console.log(b)
}

a(2)
Copy the code

Block-level scope

Block-level scope is a tool used to extend the principle of minimum exposure, extending code from hiding information within functions to hiding information within blocks.

Take a common example

for(var i = 0; i<996; i++){console.log(i)
}
Copy the code

I is only used inside the for loop, but contaminating the whole function scope. If we use block-level scope, we can only use it inside the for loop, which is a great benefit to ensure that variables are not reused in a disorderly manner and to improve the maintainability of the code.

try/catch

The catch clause of the TRY /catch clause in the ES3 specification creates a block-level scope where declared variables are only valid for catch

try{
    undefined(a)// Execute whatever it takes to make him fail
}
catch(e){
    console.log(e) // Can be executed normally
}

console.log(e) //VM20919:8 Uncaught ReferenceError: e is not defined
Copy the code

let

The let keyword is provided in ES6 to bind variables to any scope, usually the {… }.

That is, the let keyword can implicitly create block scope for the variables it declares.

const

In addition to lets, ES6 introduces const, which can also be used to create block-scoped variables, but whose value is fixed. Any subsequent modification of the value throws an error.

The last

These are my views on scope. If you have any questions or suggestions, please leave a comment!

By the way, I would like to recommend varlet, the open source project I participated in. Welcome to star PR