Home  >  Article  >  Web Front-end  >  Analysis of execution context and variable objects in js

Analysis of execution context and variable objects in js

不言
不言Original
2018-08-14 10:02:021176browse

The content this article brings to you is about the analysis of execution context and variable objects in js. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Execution Context(Execution Context)

The process of JavaScript code execution includes two stages: compilation and execution. Compilation is to build an abstract abstract syntax tree through lexical analysis. And compiled into machine-recognized instructions. In the JavaScript code compilation phase, the scope rules have been determined; in the code execution phase, or once the function is called, an execution context (Execution Context) will be created, also called execution environment

There is the following definition in ECMA-262

When the controller switches to the executable code of the ECMA script, the controller will enter an execution environment. Multiple currently active execution environments logically form a stack structure. The top-level execution environment of the logical stack is called the currently running execution environment. Any time the controller transitions from executable code that is dependent on the currently running execution environment to executable code that is independent of that execution environment, a new execution environment is created. The newly created execution environment will be pushed into the stack and become the currently running execution environment.

This is also an abstract concept. In a piece of JavaScript code, multiple execution contexts will be created. The execution context defines variables or Other data that the function has access to. By reading the specifications and related documents, we learned that the execution context (EC for short) mainly includes three points, which are expressed in pseudo code as follows:

EC = {
    this: // 绑定this指向为当前执行上下文, 如果函数属于全局函数,则this指向window
    scopeChain: [] // 创建当前执行环境的作用域链,
    VO: {} // 当前环境的变量对象(Variable Object),每个环境都有一个与之关联的变量对象
}

Look at the following code:

var a = 1;
function foo() {
    var b = 2;
    function bar() {
        console.log(b)
    }
    bar()
    console.log(a);
}

foo()
  • 1. When executing this code, the global context globalEC will first be created and pushed into the execution context stack;

  • 2. When calling When foo(), the context fooEC of foo will be created and pushed into the execution context stack;

  • #3. When bar() is called, the context barEC of bar will be created and pushed. into the execution context stack;

  • 4. When the bar function is executed, barEC will pop up from the execution context stack;

  • 5. When the foo function is executed, fooEC will pop up from the execution context stack;

  • 6. After the browser window is closed, the global context glbleEC will pop up from the execution context stack;

Summary: The bottom of the stack is always the global context, and the top of the stack is the currently executing context. Only when the browser is closed, the global context will pop up from the execution context stack

Variable Object:

Each execution environment has a variable object associated with it. It is an abstract concept. All variables defined in the environment and Functions are stored in this object. Although the code we write has no access to this object, the single parser uses them behind the scenes when processing the data.

When the browser loads the js script program for the first time, it enters the global execution environment by default. This time, the global environment variable object is window and can be accessed in the code.

If the environment is a function, this active object will be used as the variable object of the current context (VO = AO). At this time, the variable object cannot be accessed through code. The following mainly explains the active object.

Activation Object(Activation Object)

1. Initialize the activity object (hereinafter abbreviated as AO)

When the function is called, the current object is created immediately The active object of the context, and the active object is used as a variable object, initialized through the arguments attribute, and the value is the arguments object (the set of actual parameters passed in, has nothing to do with the formal parameters, the formal parameters are defined as local variables of the local environment)

The
AO = {
  arguments: <ArgO>
};

arguments object has the following properties:

  • length: The number of parameters actually passed;

  • callee: Points to the reference of the current function, that is, the called function;

  • 'Class index': Integer of string type, value It is the value of the object subscript in the arguments object. The arguments object should be distinguished from the array. It is the arguments object, but it can have the same length attribute as the array, and the value can be accessed through the subscript

function show (a, b, c) {
    // 通过Object.prototype.toString.call()精准判断类型, 证明arguments不同于数组类型
    var arr = [1, 2, 3];
    console.log(Object.prototype.toString.call(arr)); // [object Array]

    console.log(Object.prototype.toString.call(arguments)); // [object Arguments]

    console.log(arguments.length) // 2  传递进来实参的个数

    console.log(arguments.callee === show) // true 就是被调用的函数show自身

    //参数共享

    console.log(a === arguments[0]) // true

    a = 15;

    console.log(arguments[0]) // 15

    arguments[0] = 25;

    console.log(a)  // 25;

    但是,对于没有传进来的参数c, 和arguments的第三个索引是不共享的

    c = 25;

    console.log(arguments[2]) // undefined

    argument[2] = 35;

    console.log(c) // 25

}

show(10, 20);

Go on, this is the key point. The code of the execution environment is divided into two stages to process:

  1. Enter the execution environment

  2. Code to execute the function

2. Enter the execution environment

If the function is called, enter the execution environment (context) and immediately create the active object, through The arguments attribute is initialized. At the same time, all formal parameters, all function declarations, and all variable declarations in the execution environment are scanned, added to the active object (AO), and the value of this is determined, and then the code execution begins.

At this stage of entering the execution environment:

All formal parameter declarations:

The formal parameter name is used as an active object attribute Create, if actual parameters are passed, the value is the actual parameter value, if no parameters are passed, the value is undefined

All function declarations:

The function name is used as the active object The property is created, the value is a pointer in memory, pointing to this function, if a property of the same name already exists in the variable object, it is completely replaced.

All variable declarations:

所有变量名称作为活动对象的属性被创建, 值为undefined,但是和函数声明不同的是, 如果变量名称跟已经存在的属性(形式参数和函数)相同、则不会覆盖
function foo(a, b) {
    var c = 10;
    function d() {
        console.log('d');
    }
    var e = function () {
        console.log('e');
    };
    (function f() {})
    if (true) {
        var g = 20;
    } else {
        var h = 30;
    }
}

foo(10);

此时在进入foo函数执行上下文时,foo的活动对象fooAO为:

fooAO = {
    arguments: {
        0: 10,
        length: 1
    },
    a: 10,
    b: undefined,
    c: fundefined,
    d: <d reference>  //指向d函数的指针,
    e: undefined,
    g: undefined,
    h: undefined  // 虽然else中的代码永远不会执行,但是h仍然是活动对象中的属性
}

这个例子做如下几点说明:

  • 1.关于函数,只会创建函数声明作为活动对象的属性, 而f函数作为函数表达式并不会出现在活动对象(AO)中

  • 2.e虽然值是一个函数, 但是作为变量属性被活动对象创建

3、代码执行阶段

在进入执行上下文阶段,活动对象拥有了属性,但是很多属性值为undefined, 到代码执行阶段就开始为这些属性赋值了

还是上面的代码例子, 此时活动对象如下:

fooAO = {
    arguments: {
        0: 10,
        length: 1
    },
    a: 10,
    b: undefined,
    c: 10, // 赋值为undefined
    d: <d reference>  //指向d函数的指针,
    e: <d reference>  // 指向e函数的指针
    g: 20,
    h: undefined  // 声明h变量,但是没有赋值
}

变量对象包括:{ arguments对象+函数形参+内部变量+函数声明(但不包含表达式) }

这时这个活动对象, 即作为当前执行环境的变量对象会被推到此执行环境作用域链的最前端(作用域链本篇不做介绍,会在下一篇文章中单独讲解作用域和作用域链), 假定执行环境为一个对象,则整个执行环境可以访问到的属性如下:

伪代码如下:

fooExecutionContext = {
    scopeChain: [], //fooAO +所有父执行环境的活动对象,
    fooAO: {
        arguments: {
            0: 10,
            length: 1
        },
        a: 10,
        b: undefined,
        c: 10, // 赋值为undefined
        d: <d reference>  //指向d函数的指针,
        e: <d reference>  // 指向e函数的指针
        g: 20,
        h: undefined
    },
    this: 当前执行环境的上下文指针
}

补充:

下面的例子为了说明一下变量声明的顺序及变量同名不会影响函数声明

console.log(foo); //  foo的函数体
var foo = 10;
console.log(foo) // 10
function foo() {};
foo = 20;
console.log(foo); // 20

在代码执行之前, 就会读取函数声明,变量声明的顺序在函数声明和形参声明之后, 整个流程如下:

进入执行环境阶段:

1. var VO = {}
2. VO[foo] = 'foo函数指针'
3. 扫描到var foo = 10,

 // 但是foo做为function已经声明,所以变量声明不会影响同名的函数声明,如果代码中没有foo函数声明的话,则foo为undefined

代码执行阶段:

1. VO[foo] = 10;
2. VO[foo] = 20;

解析代码完成。

相关推荐:

js对象是什么?js对象的介绍(附代码)

Js中前端模块化的详细分析及其区别对比

js中字符方法以及字符串操作方法的总结(附代码)

The above is the detailed content of Analysis of execution context and variable objects in js. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn