Home >Web Front-end >JS Tutorial >What is a JS variable object? Detailed explanation of JS variable objects and matters needing attention

What is a JS variable object? Detailed explanation of JS variable objects and matters needing attention

php是最好的语言
php是最好的语言Original
2018-07-23 11:10:502701browse

In JavaScript, what is a variable object? This article first introduces the concept of variable objects, how variable objects in context are executed, how the code in variable objects is processed, and finally what are variables?

Variable object is the bridge between execution context and scope chain.
Spoiler, the mysterious this exists in the execution context!
Of course, I will use a few separate sections later to thoroughly explain what this is (actually this is very simple).

Next, we enter the text.

1. What does the execution context include?

We can abstractly understand an execution context as an object.
Each execution context has some properties (also called context status) that are used to track the execution progress of the associated code.

I use a structure diagram to illustrate:

执行上下文环境 object

Variable Object represents the variable object.
Scope Chain represents scope chain.
thisValue represents the mysterious this.

The scope chain and this will be discussed later. Today we will first understand the variable object.

2. Variable object

A variable object is a scope of data related with the execution context. It's a special object associated with the context and which stores variables and function declarations are being defined within the context.

A variable object is the scope of data related to the execution context. It is a special object associated with a context that stores variables and function declarations defined in the context.

Variable Object (Variable Object -- VO for short) is an abstract concept that refers to a special object related to the execution context. It stores the following:
- Variable (var)
- Function declaration (function declaration, abbreviated FD)
- Formal parameters of the function (arguments)

We assume that the variable object is an ordinary ECMAScript object:

VO = {};

As mentioned before, VO is an attribute of the execution context:

activeExecutionContext = {
  VO: {
    // 上下文数据 (vars, FD, arguments)
  }
}

Because the variable object is a It is an abstract concept, so it cannot be accessed directly through the name of the variable object, but it can be accessed indirectly through other methods. For example, the variable object in the global context environment will have an attribute window (in DOM) that can refer to the variable object itself. , another attribute of the global context, this, also points to the variable object of the global context.

For example:

var a = 2;

function foo (num) {
   var b = 5;
}

(function exp () {
   console.log(111);
})

foo(10);

The corresponding variable object here is:

// 全局上下文环境的变量对象
VO(globalContext) = {
   // 一些全局环境初始化时系统自动创建的属性: Math、String、Date、parseInt等等
   ···

   // 全局上下文的变量对象中有一个属性可以访问到自身,在浏览器中这个属性是 window ,在 node 中这个属性是 global
   window: global

   // 自己定义的属性
   a: 10,
   foo: <reference to function>
};

// foo 函数上下文的变量对象
VO(foo functionContext) = {
   num: 10,
   b: 5
};

Note: Function expressions are not included in the variable object.

3. Variable objects in different execution contexts

Execution contexts include: global context, function context and eval() context.

Variable objects in the global context

Here we first understand what a global object is:

全局对象(global object)是指在进入任何执行上下文之前就已经创建了的对象。
这个对象只有一份,它的属性在程序中的任何地方都可以访问,全局对象的生命周期终止于程序退出的那一刻。

When the global object is initialized, the system will create and initialize a series of Primitive properties, such as Math, String, Date, parseInt, window, etc., followed by global variables that we define in the global context. In the DOM, the window property of the global object can refer to the global object itself, and the this property of the global context can also refer to the global object.

// 全局执行上下文环境
EC(globalContext) = {
   // 全局对象(全局上下文环境的变量对象) 
   global: {
      Math: <...>,
      String: <...>,
      ...
      ...
      window: global     // 引用全局对象自身
   },

   // this 属性
   this: global

   // 作用域链
   ...
}

For example:

var a = 10;

console.log(a);               // 10
console.log(window.a);        // 10
console.log(this.a);          // 10

Therefore, in the global context, the variable object is represented by the global object.

Variable objects in function context

In function context, variable objects are represented by active objects AO (Active Object).

VO(functionContext) = AO

The active object is created when entering the function context, and it is initialized through the arguments property of the function. arguments is also an object.

AO = {
   arguments: {
      ...
   }
}

arguments is a property of the active object. It is also an object and includes the following properties:
1. callee - a reference to the current function
2. length - the number of parameters actually passed
3. properties-indexes - index is an integer of string type, such as "1": "aa", which is similar to the array type and can also be accessed through arguments[1], but cannot use the array methods (push, pop etc). In addition, the values ​​of properties-indexes and the parameters actually passed in are shared. If one changes, the other will also change.

For example:

function foo (x, y, z) {

   // 声明的函数参数数量
   console.log(foo.length);      // 3

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

   // arguments 的 callee 属性指向当前函数
   console.log(arguments.callee === foo)   // true

   // 参数共享
   console.log(x === arguments[0]);      // true
   console.log(x);      // 10

   arguments[0] = 20;
   console.log(x);   // 20

   x = 30;
   console.log(arguments[0]);    // 30

   // 但是注意,没有传递进来的参数 z ,和第3个索引值是不共享的
   z = 40;
   console.log(arguments[2]);      // undefined

   arguments[2] = 50;
   console.log(z);      // 40
}

foo(10, 20);

4. How the code is processed

In Section 1 we talked about the compilation process of js code, one of which is called Pre-compilation means that the code will be compiled first a few microseconds before the code is executed, forming a lexical scope, and then executed.

Then the code of the execution context can be divided into two stages for processing:
1. Enter the execution context (precompiled)
2. Execute the code

而变量对象的修改变化和这两个阶段是紧密相关的。
并且所有类型的执行上下文都会有这2个阶段。

进入执行上下文

当引擎进入执行上下文时(代码还未执行),VO 里已经包含了一些属性:
1. 函数的所有形参(如果是函数执行上下文)
由名称和对应值组成的一个变量对象的属性被创建,如果没有传递对应的实参,那么由名称和 undefined 组成的一种变量对象的属性也会被创建。

2.所有的函数声明(Function Declaration - FD)
由名称和对应值(函数对象 function object)组成的一个变量对象的属性被创建,如果变量对象已经存在相同名称函数的属性,则完全替换这个属性。

3.所有的变量声明(Variable Declaration - var)
由名称和对应值(在预编译阶段所有变量值都是 undefined)组成的一个变量对象的属性被创建,如果变量名和已经声明的形参或者函数相同,则变量名不会干扰已经存在的这类属性,如果已经存在相同的变量名,则跳过当前声明的变量名。

注意:变量碰到相同名称的变量是忽略,函数碰到相同名称的函数是覆盖。

举个例子:

function test(a, b, c) {
            
    console.log(a); // 函数体a
    console.log(b);  // 20
    function a() {
         console.log(1);
    }
    var a = 100;
    console.log(a);  // 100
    var b = 2;
    console.log(b); // 2

}
test(10,20,30);
function foo (a, b) {
   var c = 5;

   function bar () {};

   var d = function _d () {};

   (function f () {});
}

foo(10);

当进入带有实参10的 foo 函数上下文时(预编译时,此时代码还没有执行),AO 结构如下:

AO(foo) = {
   a: 10,
   b: undefined,

   c: undefined,
   bar: <reference to FunctionDelcaration "bar">,
   d: undefined 
};

注意,函数表达式 f 并不包含在活动对象 AO 内。
也就是说,只有函数声明会被包含在变量对象 VO 里面,函数表达式并不会影响变量对象。

行内函数表达式 _d 则只能在该函数内部可以使用, 也不会包含在 VO 内。

这之后,就会进入第2个阶段,代码执行阶段。

代码执行

在这个阶段,AO/VO 已经有了属性(并不是所有的属性都有值,大部分属性的值还是系统默认的初始值 undefined)。

AO 在代码执行阶段被修改如下:

AO[&#39;c&#39;] = 5;
AO[&#39;d&#39;] = <reference to FunctionDelcaration "_d">

再次要提醒大家,因为函数表达式 _d 已经保存到了声明的变量 d 上面,所以变量 d 仍然存在于 VO/AO 中。我们可以通 d() 来执行函数。但是函数表达式 f 却不存在于 VO/AO 中,也就是说,如果我们想尝试调用 f 函数,不管在函数定义前还是定义后,都会出现一个错误"f is not defined",未保存的函数表达式只有在它自己的定义或递归中才能被调用。

再来一个经典例子:

console.log(x);      // function

var x = 10;
console.log(x);      // 10

x = 20;

function x () {};

console.log(x);      // 20

这里为什么是这样的结果呢?

上边我们说过,在代码执行之前的预编译,会为变量对象生成一些属性,先是形参,再是函数声明,最后是变量,并且变量并不会影响同名的函数声明。

所以,在进入执行上下文时,AO/VO 结构如下:

AO = {
   x: <reference to FunctionDeclaration "x">

   // 在碰到变量声明 x 时,因为已经存在了函数声明 x ,所以会忽略
}

紧接着,在代码执行阶段,AO/VO 被修改如下:

AO[&#39;x&#39;] = 10;
AO[&#39;x&#39;] = 20;

希望大家可以好好理解变量对象,对于理解我们后边要讲的作用域链有很大的帮助。

5. 变量

有一些文章说过:

不管是使用 var 关键字(在全局上下文)还是不使用 var 关键字(在任何地方),都可以声明一个变量。

请记住,这是错误的观念。

任何时候,变量都只能通过使用 var 关键字来声明(ES6 之前)

a = 10;

上面的赋值语句,仅仅是给全局对象创建了一个新属性(在非严格模式,严格模式下会报错),但注意,它不是变量。“不是变量”并不是说它不能被改变,而是指它不符合ECMAScript 规范中变量的概念。

让我们通过一个例子来看一下两者的区别:

console.log(a);        // undefined
console.log(b);        // 报错,b is not defined

b = 10;
var a = 20;

只要我们很好的理解了:变量对象、预编译阶段和执行代码阶段,就可以迅速的给出答案。

预编译(进入上下文)阶段:

VO = {
   a: undefined
}

我们可以看到,因为 b 不是通过 var 声明的,所以这个阶段根本就没有 b ,b 只有在代码执行阶段才会出现。但是在这个例子中,还没有执行到 b 那就已经报错了。

我们稍微更改一下示例代码:

console.log(a);      // undefined

b = 10;
console.log(b);             // 10 代码执行阶段被创建
console.log(window.b);      // 10
console.log(this.b);        // 10

var a = 20;
console.log(a);      // 20 代码执行阶段被修改

关于变量,还有一个很重要的知识点。

变量不能用 delete 操作符来删除。

a = 10;

console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined

var b = 20;
console.log(window.b);    // 20

console.log(delete b);    // false

console.log(window.b);    // 20

注意:这个规则在 eval() 上下文中不起作用。

eval(&#39;var a = 10;&#39;);
console.log(window.a);    // 10

console.log(delete a);    // true

console.log(window.a);    // undefined

 相关推荐:

 js高级面向对象和组件开发视频教程

js 多种变量定义(对象直接量,数组直接量和函数直接量)_javascript技巧

The above is the detailed content of What is a JS variable object? Detailed explanation of JS variable objects and matters needing attention. 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