首先要记住:预编译发生在函数执行的前一刻
先来一个小知识:
- 函数声明整体提升
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视频教程后对预编译的总结,如有错误请指出。