irpas技术客

AO对象与GO对象——预编译(1)_m0_46569480

irpas 4132

文章目录 JS引擎都做了什么?函数声明提升var关键字的声明提升,赋值不提升一个奇奇怪怪的例子暗示全局变量 AO对象GO对象AO和GO综合练习

JS引擎都做了什么?

1.检查通篇的语法错误(语法分析) 1.5预编译的过程(预编译) 2.解释一行执行一行(解释执行)

函数声明提升 text(); function text() { console.log(1); } // 1 var关键字的声明提升,赋值不提升

var关键字声明的变量会自动提升到函数作用域顶部。

所谓的“提升”(hoist),也就是把所有变量声明都拉到函数作用域的顶部。

此外,反复多次使用 var 声明同一个变量也没有问题。

console.log(a) // Uncaught ReferenceError: a is not defined console.log(a); var a; // undefined console.log(a); var a = 10; // undefined // 提升的仅仅是变量的声明而不是初始化

undefined和error不一样!!!

一个奇奇怪怪的例子 console.log(a); function a(a) { var a = 10; var a = function () { } } var a = 1; // 打印结果竟然不是undefined! // ? a(a) { // var a = 10; // var a = function () { // // } // } 暗示全局变量

预编译有个特点:任何变量,如果未声明就赋值,那该变量为全局变量,即暗示全局变量(imply global)。并且所有的全局变量都是window的属性。

var a = 1; b = 2; console.log(window.b); // 1 console.log(window.a); // 2 // var操作符在全局作用域下声明的变量自动变为window的对象 如a // 在函数内定义变量时省略var会创建全局变量 如b function test() { var a = b = 2; } test(); console.log(b); // 2 console.log(a); // Uncaught ReferenceError: a is not defined console.log(window.a); // undefined // 函数体先声明了一个局部变量a,然后不使用var声明了一个全局变量b,将b赋初值为2,最后用b的值初始化a // 因此b作为全局变量在函数test()外部仍能访问 // a作为局部变量,只有函数作用域 // window对象打印不存在的属性时显示undefined // 在第二局console报错时不会继续向下执行了,所以注释掉这一句 AO对象

AO对象全称为:activation object (活跃对象/执行期上下文/函数上下文),在函数执行前执行函数预编译,此时会产生一个AO对象,AO对象保存该函数的参数变量。

函数预编译步骤:

产生空的AO对象找形参和变量声明,作为AO对象的属性名,值为undefined。实参值赋值给形参。在函数里面寻找函数声明,函数名作为AO对象的属性名(若形参、变量声明与函数名重叠,则函数体值会覆盖参数值与undefined),值为函数体。

执行

// eg.1 function test(a) { console.log(a); var a = 1; console.log(a); function a() { }; console.log(a); var b = function () { }; console.log(b); function d() { }; } test(2);

创建AO对象 AO{ //此时AO对象为空 }

确定AO对象的属性名 e.g.1AO{ a:undefined; //函数参数 b:undefined; //函数里面声明的变量 }

将实参值赋值给形参 AO{ a:undefined ->

? 2 -> //函数参数 b:undefined; //函数里面声明的变量 }

处理函数里面的声明函数 AO{ a:undefined ->

? 2 ->

? function a () {} -> //函数声明提前,变量名一样,值覆盖

? 1,

b:undefined ->

? function (){}, //函数里面声明的变量 d:function d () {} }

此时函数预编译已经完成的,预编译后执行代码: 第一条执行的是控制台打印出a的值,所以输出function a () {}; 第二条语句赋值给a,则AO对象中a的值被覆盖为2; 第三条语句控制台打印a的值为1; 第四条为声明,预编译处理过所以直接跳过; 第五条打印出a的值,一样为1; 第六条为赋值,赋值b的值为function () {}; 第七条打印出b的值function () {}; 第八条声明,预编译处理过所以直接跳过;

所以输出结果应该是 function a () {}; 1; 1; function () {}; 执行效果如图:

// eg.2 function test(a, b) { console.log(a); c = 0; var c; a = 5; b = 6; console.log(b); function b() { }; function d() { }; console.log(b); } test(1); AO = { a: undefined -> 1 -> // 此时打印第一个console 5, b: undefined -> function b() { } -> 6, // 此时打印第二个console,并且由于下面对b()的函数声明 //在预处理时做过了,直接pass,第三个console也输出这个b c: undefined -> 0, d: function d() { }, } GO对象

GO对象全称为 global object(全局对象,等同于window),在开始预编译时产生的对象,比AO对象先产生,用于存放全局变量,也称为全局作用域。

预编译之前进行

生成空的GO对象将变量声明的变量名当做GO对象的属性名,值为undefinded将声明函数的函数名当做GO对象的属性名,值为函数体 console.log(a); var a = 123; function a() { } console.log(a); // GO: { // a: undefined -> // function a() { } -> // 此时执行第一句console,预编译结束 // 123, //此时执行第二句console // }

AO和GO综合练习

1.求输出结果

console.log(a); // undefined a = 100; function test() { console.log(a); // undefined a = 200; console.log(a); // 200 var a = b = 300; } test(); console.log(b); // 300 var a; console.log(a); //100 GO: { a: undefined -> 100, function test() { }, b: undefined -> 300, } AO: { a: undefined -> 200 -> 300, }

生成GO对象 GO{ }

将声明变量添加进GO对象内,值为undefined GO{ a:undefined; }

将声明函数添加进GO对象呢,值为函数体 GO{ a:undefined; function test() { … }; }

预编译完成,执行代码:输出a,此时a的值为:undefined

a赋值,此时GO对象内的a值变为100 GO{ a:100; function test() { … }; }

执行函数test(),生成AO对象 AO{

}

将函数声明的变量添加进AO对象,值为undefined AO{ a:undefined; }

函数没有传递参数,跳过函数预编译的第三步

函数里面没有声明函数,跳过函数预编译的第四步

执行函数,打印a,此时AO里面有属性a,则输出AO里面a的值,即输出: undefined

AO的a赋值200,此时AO的a的值为200 AO{ a:200; }

输出a的值:200

将300的值赋值给b再赋值给a,此时b未声明,所以b为全局变量,将b添加进GO对象内,将a的值改为300 GO{ a:100; function test() { … }; b:300; } AO{ a:300; }

输出a的值:300,函数执行完成

输出b的值:300

输出a的值,此时a的值为GO里面的值:100

2.求输出结果

//GO{ //生成的GO对象 //a:undefined; //test:function test(){ ... }; //} function test() { console.log(b);//undefined if (a) {//AO里面没有a的属性,自动寻找GO里面a的属性,此时a的值为undefined,语句不执行 var b = 50; } console.log(b);//undefined c = 100;//未声明则为全局变量,添加在GO对象内 console.log(c); //100 } var a; test();//执行函数预编译 //AO{ //生成的AO对象 //b:undefined; //} a = 10;//GO里面的a赋值为10 console.log(c);//100 function test() { return a; a = 1; function a() { var a = 2; } } console.log(test()); // AO: { // a: function a() { }, // } //? a() { // var a = 2; // } function test() { a = 1; function a() { }; var a = 2; return a; } console.log(test()); // AO: { // a: undefined -> // a(){ } -> // 1 -> // 2, // } a = 1; function test(e) { function e() { } arguments[0] = 2; //与实参同步 console.log(e); //2 if (a) { var b = 3; // 这里也会变量提升,不要忘记 } var c; a = 4; var a; console.log(b); //undefined f = 5; console.log(c); // undefined console.log(a); // 4 } var a; test(1); // GO: { // a: undefined -> // 1, // test: test(){ }, // } // AO: { // e: undefined -> // 1 -> // e(){ } -> // 2, // b: undefined, // c: undefined, // a: undefined -> // 4, // }

AO、GO实际上是为了解决作用域、作用域链相关所产生的一切问题


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #AO对象与GO对象预编译1 #Text #consolelog1