JavaScript goes deep into the scope chain

未进入执行阶段之前,变量对象(VO)中的属性都不能访问!但是进入执行阶段之后,变量对象(VO)转变为了活动对象(AO),里面的属性都能被访问了,然后开始进行执行阶段的操作。

它们其实都是同一个对象,只是处于执行上下文的不同生命周期。

When JavaScript code executes a piece of executable code, a corresponding execution context is created.

For each execution context, there are three important properties:

  • Variable object (Variable object, VO)
  • Scope chain
  • this

The previous article mainly talked about variable objects

This article talks about the scope chain of the execution context

scope chain

When searching for a variable, it will first search from the variable object of the current context. If it is not found, it will search from the variable object of the execution context of the parent (the parent at the lexical level), and always find the variable object of the global context. That is, the global object. Such a linked list consisting of variable objects of multiple execution contexts is called a scope chain.

When code is executed in an environment, a scope chain of variable objects is created. The purpose of a scope chain is to guarantee ordered access to all variables and functions that the execution environment has access to.

Next, let us explain how the scope chain is created and changed in two periods of creation and activation of a function.

function creation

Because JavaScript is statically scoped, the scope of a function is determined when the function is defined.

This is because the function has an internal property [[scope]], when the function is created, it will save all the parent variable objects into it, you can understand[[scope]] 就是所有父变量对象的层级链

But note: [[scope]] does not represent a complete scope chain!

The main [[scope]] here must be the upper scope chain of the function!!

Example:

function foo() {
    function bar() {
        ....
    }
}

When the function is created, the respective parent scope chain is like this


foo.[[scope]] = [
    globalCotext.VO   //相当于父级是windows 变量对象
]
bar.[[scope]] = [
    fooContext.AO,    //bar() 的父级是foo 再父级是 全局  为活动对象
    globalContext.VO
];

The scope chain in the function body is created

function activation

When the function is activated, enter the function context, after creating VO/AO,就会将活动对象添加到作用链的前端。

At this time, the scope chain of the execution context, we name it Scope:

Add [AO] to the top of the scope

Scope = [AO].concat([[Scope]]);

The scope chain has been created at the time of creation

Maybe most people here don't quite understand it, and I understand it for a long time.

Popular point explanation (refer to js advanced programming P73)

When code is executed in an environment, a scope chain is created. The purpose of a scope chain is to guarantee ordered access to all variables and functions that the execution environment has access to. The essence of the entire scope chain is a list of pointers to variable objects. The front end of the scope chain is always the variable object of the environment where the currently executing code is located.

The execution environment book about function creation says so

Execution environment is one of the important concepts in JavaScript. The execution environment defines the other data that the variable or function has access to, which determines their respective behavior. Each execution environment has a variable object associated with it, and all variables and functions defined in the environment are stored in this object.
The global execution environment is the outermost execution environment. In a web browser, the global execution environment is considered the window object, so all global variables and functions are created as properties and methods of the window object. When all code in an execution environment is finished executing, the environment is destroyed, along with all variables and function definitions stored in it (the global execution environment is not destroyed until the application exits—such as closing a web page or browser. destroy)
Each function has its own execution environment . When the flow of execution enters a function, the function's environment is pushed onto an environment stack. And after the function is executed, the stack pops its environment, returning control to the previous execution environment.
The establishment of the execution environment is divided into two stages: entering the execution context (creation stage) and execution stage (activation/execution stage)
(1) Entering the context stage: occurs when the function is called, but before the specific code is executed. Concretely complete the creation of the scope chain; create variables, functions and parameters, and find the value of this
(2) Execution code stage: mainly complete variable assignment, function reference and interpretation/execution of other code
In general, the execution context can be regarded as a object

EC = {
    VO:{/*函数中的arguments对象、参数、内部变量以及函数声明*/}
    this:{},
    Scope:{/*VO以及所有父执行上下文中的VO*/}

Taking the following example as an example, combined with the variable object and execution context stack mentioned earlier, let's summarize the creation process of the scope chain and variable object in the function execution context:

var scope = "global scope";
function checkscope(){
    var scope2 = 'local scope';
    return scope2;
}
checkscope();
  1. The checkscope function is created to save the scope chain to the inner property [[scope]]
checkscope.[[scope]] = [
    globalContext.VO     //父级作用域为全局作用域
];
  1. Execute the checkscope function, create the checkscope function context, and the checkscope function execution context is pushed into the execution context stack
ECStack = [
    checkscopeContext,    //进入执行上下文栈
    globalContext
];
  1. The checkscope function does not execute immediately, start to prepare, the first step: copy the function [[scope]] attribute to create a scope chain
checkscopeContext = {
    Scope: checkscope.[[scope]],       //获取作用域链
}
  1. Step 2: Create an active object with arguments, then initialize the active object, add formal parameters, function declarations, and variable declarations
checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: undefined 
    }Scope: checkscope.[[scope]],
}
  1. Step 3: Push the live object to the top of the checkscope scope chain
checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: undefined
    },
    Scope: [AO, [[Scope]]]      //将当前函数的活动对象加入作用链
}

6. After the preparatory work is completed, 开始执行函数, with the execution of the function, modify the attribute value of AO

checkscopeContext = {
    AO: {
        arguments: {
            length: 0
        },
        scope2: 'local scope'   //执行代码的时候 赋值
    },
    Scope: [AO, [[Scope]]]
}

Find the value of scope2, after returning, the function execution is completed, and the function context is popped from the execution context stack

ECStack = [
    globalContext   //执行完毕 弹出栈
];

As a very important concept in JavaScript, the scope chain can be understood by referring to JavaScript Advanced Programming P73 (Execution Environment and Scope)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325347636&siteId=291194637