Advanced Front-end Basics (3): Detailed Explanation of Variable Objects

After the beginning of the year, the enthusiasm for work has not been very high, and I have been in a state of passive sabotage these days. I don't want to get up in the morning, I don't want to go to work when I get up. Obviously, before the holiday, the enthusiasm for work was still very high, and I always wanted to get rid of the small program project, but the style of painting was completely different after returning from the holiday. I feel like I have severe post-holiday syndrome. Fortunately, I wrote a few articles, reluctantly saying that this week's time was not completely wasted. This article will introduce you to variable objects.

In JavaScript, we certainly inevitably need to declare variables and functions, but how does the JS parser find these variables? We also have to have a further understanding of the execution context.

In the previous article, we already know that when a function is called (activated), a new execution context is created. The life cycle of an execution context can be divided into two phases.

  • Creation phase  In this phase, the execution context creates variable objects, establishes a scope chain, and determines the point of this.

  • After the code execution phase  is created, the code will be executed. At this time, variable assignment, function reference, and other code will be executed.

Execution context life cycle

From here, we can see that it is extremely important to understand the execution context in detail, because it involves variable objects, scope chains, this, etc. Many people do not understand very well, but they are extremely important concepts, which are related to whether we can really understand JavaScript. . In the following articles, we will summarize them in detail, but here we will focus on understanding variable objects first.

Variable Object

The creation of variable objects goes through the following processes in turn.

  1. Create the arguments object. Check the parameters in the current context, and establish the properties and property values ​​under the object.

  2. Checks for function declarations in the current context, that is, functions declared with the function keyword. Create an attribute in the variable object with the function name, and the attribute value is a reference to the memory address where the function is located. If an attribute of function-name already exists, that attribute will be overwritten by the new reference.

  3. Check the variable declarations in the current context, and each time a variable declaration is found, a property is created in the variable object with the variable name, and the property value is undefined. If the attribute of the variable name already exists, in order to prevent the function of the same name from being modified to undefined, it will be skipped directly, and the original attribute value will not be modified.

Many readers will have doubts about the word "skip" when reading this because of the following scenarios. Since foo declared in a variable encounters foo declared in a function, it will be skipped, but why is the final output of foo still overwritten?

function foo() { console.log('function foo') } var foo = 20; console.log(foo); // 20 

In fact, everyone is not careful enough when reading, because the above three rules only apply to the creation process of variable objects. That is, the creation process of the execution context. Insteadfoo = 20 , it runs during the execution of the execution context, and the output will naturally be 20. Compare the example below.

console.log(foo); // function foo
function foo() { console.log('function foo') } var foo = 20; 
// 上栗的执行顺序为

// 首先将所有函数声明放入变量对象中
function foo() { console.log('function foo') } // 其次将所有变量声明放入变量对象中,但是因为foo已经存在同名函数,因此此时会跳过undefined的赋值 // var foo = undefined; // 然后开始执行阶段代码的执行 console.log(foo); // function foo foo = 20; 

I know some people don't like to read text

According to this rule, understanding variable hoisting becomes very simple. Although variable promotion is mentioned in many articles, many people can't tell what is going on. In the future, the creation process of variable objects will be used in the interview to explain variable promotion to the interviewer to ensure instant promotion.

In the above rules, we can see that function declarations take precedence over var declarations. In order to help you better understand the variable object, we will discuss it with some simple examples.

// demo01
function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test(); 

In the above example, we start understanding directly from the execution context of test(). When running in the global scope test(), the execution context for test() is created. For ease of understanding, we use the following form to express

// 创建过程
testEC = {
    // 变量对象
    VO: {},
    scopeChain: {}
}

// 因为本文暂时不详细解释作用域链,所以把变量对象专门提出来说明

// VO 为 Variable Object的缩写,即变量对象
VO = {
    arguments: {...}, //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解,我做了这样的处理 foo: <foo reference> // 表示foo的地址引用 a: undefined } 

Before entering the execution phase, the properties in the variable object cannot be accessed! But after entering the execution phase, the variable object is transformed into an active object, and the properties in it can be accessed, and then the operations in the execution phase begin.

In this way, if you are asked what is the difference between the variable object and the active object during the interview, you can answer freely. They are actually the same object, but in different life cycles of the execution context. However, only variable objects in the execution context at the top of the function call stack will become active objects.

// 执行阶段
VO ->  AO   // Active Object
AO = {
    arguments: {...},
    foo: <foo reference>, a: 1, this: Window } 

Therefore, in the above example demo1, the execution order becomes like this

function test() {
    function foo() { return 2; } var a; console.log(a); console.log(foo()); a = 1; } test(); 

Another example to consolidate our understanding.

// demo2
function test() { console.log(foo); console.log(bar); var foo = 'Hello'; console.log(foo); var bar = function () { return 'world'; } function foo() { return 'hello'; } } test(); 
// 创建阶段
VO = {
    arguments: {...},
    foo: <foo reference>, bar: undefined } // 这里有一个需要注意的地方,因为var声明的变量当遇到同名的属性时,会跳过而不会覆盖 
// 执行阶段
VO -> AO
VO = {
    arguments: {...},
    foo: 'Hello',
    bar: <bar reference>, this: Window } 

You need to combine the above knowledge and carefully compare the changes of the variable object from the creation stage to the execution stage in this example. If you have understood it, it means that the variable object-related things are not difficult for you.

variable object of the global context

Take the browser as an example, the global object is window. The global context has a special place, its variable object, which is the window object. And this special, also applies to this point, this also points to window.

// 以浏览器中为例,全局对象为window
// 全局上下文
windowEC = {
    VO: Window,
    scopeChain: {},
    this: Window
}

In addition, the life cycle of the global context is consistent with the life cycle of the program. As long as the program does not end, such as closing the browser window, the global context will always exist. All other contexts can directly access the properties of the global context.

Guess you like

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