首先要记住:预编译发生在函数执行的前一刻
先来一个小知识:
- 函数声明整体提升
test(); function test(){ ...//省略n行代码 }
在预编译阶段,会把函数声明提升到代码顶部:
function test(){ .... } test();
- 变量声明提升
console.log(a); var a=123;
在预编译阶段,会把var声明提升到代码段的顶端:
var a; console.log(a); a=123;
控制台输出 undefined
但上面两点在遇到下面这种情况时就不够用了
function fn(a){ console.log(a); var a=123; console.log(a); function a() {} console.log(a); var b=function () {} console.log(b) function d() {} } fn(1);
接下来就是预编译表演的时刻了:
- 创建AO(Activation Object----活跃对象)对象(另一个名称叫执行期上下文)
AO{ }
- 找形参和变量声明,将变量和形参名作为AO属性名,值为
undefined
AO{ a:undefind,//形参和变量重名时,不需要重复创建 b:undefind }
- 将实参值和形参统一
AO{ a:1, b:undefind }
- 在函数体里找函数声明,函数名为AO属性名,值为函数体
AO{ a:function a() {},//当函数名重名时,不需要重复创建,直接赋值即可 b:undefind, d:function () {} }
原函数变为(忽略变量声明与函数声明):
function fn(a){ console.log(a);//从AO中取a的值为function a() {} a=123;//把123赋给给AO中的a console.log(a);//此时a为123 console.log(a);//还是123 b=function () {}//把函数体赋给AO中的b console.log(b)//function b() {} function d() {} } fn(1);
再来一个例子
function test(a,b){ console.log(a); c=0; var c; a=3; b=2; console.log(b); function b() {} function d() {} console.log(b); } test(1);
- 创建AO对象
AO{ }
- 找形参和变量声明,将变量和形参名作为AO属性名,值为
undefined
AO{ a:undefind, b:undefind, c:undefind }
- 将实参值和形参统一
AO{ a:1, b:undefind, c:undefind }
- 在函数体里找函数声明,函数名为AO属性名,值为函数体
AO{ a:1, b:function b() {}, c:undefind, d:function d() {} }
原函数变为(忽略变量声明与函数声明):
function test(a,b){ console.log(a);//AO中a的值为1 c=0;//0赋给AO中的c a=3;//3赋给AO中的a b=2;//2赋给AO中的b console.log(b);//AO中b的值为2 console.log(b);//2 } test(1);
练习:
function test(a,b){ console.log(a); console.log(b); var b=234; console.log(b); a=123; console.log(a); function a() {} var a; b=345; var b=function b() {} console.log(a); console.log(b); } test(1);
AO{ a:function a() {}, b:undefind }
(忽略变量声明与函数声明)
function test(a,b){ console.log(a);//function a() {} console.log(b);//undefind b=234; console.log(b);//234 a=123; console.log(a);//123 b=345; b=function b() {} console.log(a);//123 console.log(b);//function b() {} } test(1);
上面只是讲述在函数中的预编译,接下来加入全局的,中间插播一段作用域的小知识
- 一切声明的全局变量,都是
window
的属性
var a = 3; ===> window.a = 3;
- 所有未经声明就赋值的变量都是全局变量
1. a=3; 2. var a = b = 3;//b未声明就赋值
回到我们的预编译
var a=123; function a() { var a=b=3; } a();
- 生成一个GO(Global Object---全局对象)对象
GO{ a:123, b=3;//未经声明的变量赋值为全局变量 } GO ===> window
- 执行a(),生成AO对象
让我们来熟悉一下全局对象
var a=100; function fn() { console.log(a); } fn();
- 生成GO
GO{ a:100, fn:function fn() {} }
- 执行fn()前一刻生成AO对象
AO{ }
- 执行fn()
首先在自己的AO中找a属性 AO{ } AO中没有,去上一级GO中找 GO{ a:100, fn:function fn() {} } 找到a,控制台打印100
举个栗子:
console.log(test); function test(test){ console.log(test); var test=234; console.log(test); function test() {} } test(1); var test =123;
- 生成GO,生成的过程步骤与AO一样
GO{ test:function test() {} }
console.log(test);//function test() {} function test(test){ ... } test(1); var test =123;
- 执行到test(1)前一刻,生成AO
AO{ test:function test() {} }
- 执行test(1)(忽略变量声明与函数声明)
function test(test){ console.log(test);//首先会在自己的AO中找是否有test属性,有就用自己的,没有就去GO中找,此时AO中有test,值为function test() {} test=234; console.log(test);//234 }
以上为本人观看成哥javascript视频教程后对预编译的总结,如有错误请指出。