Maison > Article > interface Web > Qu'est-ce qu'un objet variable JS ? Explication détaillée des objets variables JS et des questions nécessitant une attention particulière
En JavaScript, qu'est-ce qu'un objet variable ? Cet article présente d'abord le concept d'objets variables, comment les objets variables en contexte sont exécutés, comment le code des objets variables est traité et enfin que sont les variables ? L'
Objet variable est le pont entre le contexte d'exécution et la chaîne de portée.
Alerte spoiler, le mystérieux ceci existe dans le contexte de l'exécution !
Bien sûr, je passerai quelques sections plus tard pour expliquer en profondeur ce que c'est (en fait, c'est très simple).
Ensuite, entrons dans le texte principal.
1. Que comprend le contexte d'exécution ?
Nous pouvons comprendre de manière abstraite un contexte d'exécution en tant qu'objet.
Chaque contexte d'exécution possède certaines propriétés (également appelées état de contexte) qui sont utilisées pour suivre la progression de l'exécution du code associé.
J'utilise un diagramme de structure pour illustrer :
Objet variable représente l'objet variable.
Scope Chain représente la chaîne de portée.
thisValue représente le mystérieux this .
La chaîne de portée et cela sera discuté plus tard. Aujourd'hui, nous allons d'abord comprendre l'objet variable.
2. Objet variable
Un objet variable est une étendue de données liée au contexte d'exécution. C'est un objet spécial associé au contexte et qui stocke les variables et les déclarations de fonction. défini dans le contexte.
Un objet variable est la portée des données liées au contexte d'exécution. Il s'agit d'un objet spécial associé à un contexte qui stocke les variables et les déclarations de fonctions définies dans le contexte.
Variable Object (Variable Object -- VO en abrégé) est un concept abstrait qui fait référence à un objet spécial lié au contexte d'exécution. :
- Variable (var)
- Déclaration de fonction (déclaration de fonction, en abrégé FD)
- Paramètres formels de la fonction ( arguments)
Nous supposons que l'objet variable est un objet ECMAScript ordinaire :
VO = {};
Comme mentionné précédemment, VO est un attribut du contexte d'exécution :
activeExecutionContext = { VO: { // 上下文数据 (vars, FD, arguments) } }
Parce que l'objet variable est un concept abstrait, il n'est donc pas accessible directement via le nom de l'objet variable, mais il est accessible indirectement via d'autres méthodes. Par exemple, l'objet variable dans l'environnement de contexte global aura une fenêtre d'attributs. (dans DOM). Se référant à l'objet variable lui-même, un autre attribut du contexte global, ceci pointe également vers l'objet variable du contexte global.
Par exemple :
var a = 2; function foo (num) { var b = 5; } (function exp () { console.log(111); }) foo(10);
L'objet variable correspondant ici est :
// 全局上下文环境的变量对象 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 };
Remarque : les expressions de fonction ne sont pas incluses dans l'objet variable.
3. Objets variables dans différents contextes d'exécution
Les contextes d'exécution incluent : le contexte global, le contexte de fonction et le contexte eval().
Objets variables dans le contexte global
Ici, nous comprenons d'abord ce qu'est un objet global :
全局对象(global object)是指在进入任何执行上下文之前就已经创建了的对象。 这个对象只有一份,它的属性在程序中的任何地方都可以访问,全局对象的生命周期终止于程序退出的那一刻。
Le système créera et initialisera l'objet global lorsque il est initialisé. Une série de propriétés primitives, telles que Math, String, Date, parseInt, window, etc., suivies de variables globales que nous définissons nous-mêmes dans le contexte global. Dans le DOM, la propriété window de l'objet global peut faire référence à l'objet global lui-même, et la propriété this du contexte global peut également faire référence à l'objet global.
// 全局执行上下文环境 EC(globalContext) = { // 全局对象(全局上下文环境的变量对象) global: { Math: <...>, String: <...>, ... ... window: global // 引用全局对象自身 }, // this 属性 this: global // 作用域链 ... }
Par exemple :
var a = 10; console.log(a); // 10 console.log(window.a); // 10 console.log(this.a); // 10
Par conséquent, dans le contexte global, les objets variables sont représentés par des objets globaux.
Objets variables en contexte de fonction
En contexte de fonction, les objets variables sont représentés par des objets actifs AO (Active Object).
VO(functionContext) = AO
L'objet actif est créé lors de l'entrée dans le contexte de la fonction. Il est initialisé via la propriété arguments de la fonction. les arguments sont aussi un objet.
AO = { arguments: { ... } }
arguments est un attribut de l'objet actif, qui est également un objet, comprenant les attributs suivants :
appelé - une référence à la fonction actuelle
2. nombre de paramètres réellement transmis Nombre
3. propriétés-index - l'index est un entier de type chaîne, tel que "1": "aa", qui est similaire au type tableau et est également accessible via des arguments[1] , mais la méthode array (push) ne peut pas être utilisée , pop, etc.). De plus, les valeurs des index de propriétés et les paramètres réellement transmis sont partagés. Si l'un change, l'autre changera également.
Par exemple :
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. Comment le code est traité
Dans la section 1, nous avons parlé du processus de compilation du code js, il y a une étape qui s'appelle précompilation, ce qui signifie que le code sera d'abord compilé quelques microsecondes avant d'être exécuté, formant une portée lexicale, puis exécuté.
Ensuite, le code du contexte d'exécution peut être divisé en deux étapes pour le traitement :
1. Entrez le contexte d'exécution (précompilé)
Exécutez le 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['c'] = 5; AO['d'] = <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['x'] = 10; AO['x'] = 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('var a = 10;'); console.log(window.a); // 10 console.log(delete a); // true console.log(window.a); // undefined
相关推荐:
js 多种变量定义(对象直接量,数组直接量和函数直接量)_javascript技巧
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!