Ce que cet article vous apporte concerne l'analyse du contexte d'exécution et des objets variables dans js. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Contexte d'exécution
Le processus d'exécution du code JavaScript comprend deux étapes : la compilation et l'exécution consistent à construire un arbre de syntaxe abstraite par analyse lexicale et compilé dans. instructions reconnues par la machine. Dans la phase de compilation du code JavaScript, les règles de portée ont été déterminées ; dans la phase d'exécution du code, ou une fois la fonction appelée, un contexte d'exécution (Execution Context) sera créé, également appelé environnement d'exécution
Il y a la définition suivante dans ECMA-262
Lorsque le contrôleur passe au code exécutable du script ECMA, le contrôleur entrera dans un environnement d'exécution. Plusieurs environnements d'exécution actuellement actifs forment logiquement une structure de pile. L'environnement d'exécution le plus élevé de la pile logique est appelé environnement d'exécution en cours d'exécution. Chaque fois que le contrôleur passe d'un code exécutable dépendant de l'environnement d'exécution en cours d'exécution à un code exécutable indépendant de cet environnement d'exécution, un nouvel environnement d'exécution est créé. L'environnement d'exécution nouvellement créé sera poussé dans la pile et deviendra l'environnement d'exécution en cours d'exécution
Il s'agit également d'un concept abstrait dans un morceau de code JavaScript, plusieurs contextes d'exécution seront créés. variables ou autres données auxquelles la fonction a accès. En lisant les spécifications et les documents associés, nous avons appris que le contexte d'exécution (EC en abrégé) comprend principalement trois points, qui s'expriment en pseudo code comme suit :
EC = { this: // 绑定this指向为当前执行上下文, 如果函数属于全局函数,则this指向window scopeChain: [] // 创建当前执行环境的作用域链, VO: {} // 当前环境的变量对象(Variable Object),每个环境都有一个与之关联的变量对象 }
Regardez le morceau de code suivant :
var a = 1; function foo() { var b = 2; function bar() { console.log(b) } bar() console.log(a); } foo()
1. Lors de l'exécution de ce code, le contexte global globalEC sera d'abord créé et poussé dans la pile de contexte d'exécution
Objet variable :
Chaque environnement d'exécution est associé à un objet variable, qui est un concept abstrait défini dans l'environnement. Toutes les variables et fonctions sont stockées dans cet objet. Bien que le code que nous écrivons n’ait pas accès à cet objet, l’analyseur unique les utilise en coulisse lors du traitement des données. Lorsque le navigateur charge le programme de script js pour la première fois, il entre par défaut dans l'environnement d'exécution global. Cette fois, l'objet variable d'environnement global est window et est accessible dans le code. Si l'environnement est une fonction, cet objet actif est utilisé comme objet variable du contexte actuel (VO = AO A ce moment, l'objet variable n'est pas accessible via le code. objet actif.Objet d'activation (Objet d'activation)
1. Initialisez l'objet d'activité (ci-après abrégé en AO)Lorsque la fonction est appelée, le courant L'objet est créé immédiatement L'objet actif du contexte, et l'objet actif est utilisé comme objet variable, initialisé via l'attribut arguments, et la valeur est l'objet arguments (l'ensemble des paramètres réels transmis n'a rien à voir avec le paramètres formels, les paramètres formels sont définis comme des variables locales de l'environnement local)
AO = { arguments: <ArgO> };
longueur : Le nombre de paramètres réellement passés ;
appelé : fait référence à une référence à la fonction actuelle, qui est la fonction appelée ;
'class index': entier de type chaîne, la valeur est la valeur de l'indice de l'objet dans l'objet arguments. L'objet arguments doit être distingué du tableau. objet, mais il peut avoir le même attribut de longueur que le tableau, et la valeur est accessible via l'indice
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);
Au stade de l'entrée dans l'environnement d'exécution :
Toutes les déclarations formelles de paramètres :
Les noms de paramètres formels sont utilisés comme attributs d'objet actifs Créer, si les paramètres réels sont passés, la valeur sera la valeur réelle du paramètre, si aucun paramètre n'est passé, la valeur sera indéfinieToutes les déclarations de fonction :
Nom de la fonction comme objet actif La propriété est créée, la valeur est un pointeur en mémoire, pointant vers cette fonction, si une propriété du même nom existe déjà dans l'objet variable, elle est complètement remplacée.Toutes les déclarations de variables :
所有变量名称作为活动对象的属性被创建, 值为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;
解析代码完成。
相关推荐:
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!