预编译:先扫描代码,语法分析
变量 函数提升
函数声明整体提升:函数不管写到哪里,都会被提到逻辑的最前面。所以不管在哪
里调用,本质上都是在后面调用
变量 声明提升,赋值不提升:把 var a 提升到最前面
test();
function test(){
console.log(‘a’);
}
console.log(a); //undefined 不会报错
var a = 123;
全局变量 window global
.imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为 全局对象(就是 window)所有
a = 10; ===> windows.a = 10;
function test() {
b = 123
}
test()
console.log(b)//123
b = 123
console.log(b)//123
var a = b = 234;
function test(){
var a = b = 123;
}
test()
写 test()代表执行 test,赋值是自右向左的,上面先把 123 赋给 b 的时候,b 未经声明,
然后再声明 a,再 b 的值赋给 a,导致 b 未经声明,所以 b 归 window 所有
访问 window.a 是 undefined,访问 window.b 是 123
一切声明的全局变量,全是 window 的属性,window 就是全局的域
定义全局变量,就是把a放入window对象
var a = 123; ===> window.a = 123;
预编译过程
函数预编译
预编译发生在函数执行的前一刻
function fn(a) {
console.log(a) //function() {}
var a = 123
console.log(a) //123
function a() {}
console.log(a) //123
var b = function() {}
console.log(b) //function () {}
function d() {}
}
fn(1)
- 创建 AO 对象 Activation Object(执行期上下文,作用是理解的作用域,函数产生 的执行空间库)
找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined
AO{
a : undefined,
b : undefined
}
将实参值和形参统一(把实参值传到形参里)
AO{
a : 1,
b : undefined
}
在函数体里面找函数声明,提升函数声明并将函数体赋予函数名,function a () {}和 function d () {}都是函数声明,但是 var b = function (){}不是声明而是函数表达式所以不提升,a函数提升覆盖了形参的值
AO{
a : function a() {},
b : undefined,
d : function d() {}
}
执行第一行 console.log(a);时,用的是
AO{
a : function a() {},
b : undefined,
d : function d() {}
}
执行 var a =123;改变的是
AO{
a : 123,
b : undefined,
d : function d() {}
}
在 b = function (){}时
AO{
a : 123,
b : function () {},
d : function d() {}
}
function test() {
var a = 123
function a() {}
console.log(a) //123
}
test()
AO{
a : undefined
}
AO{
a : function a() {}
}
//-----------预编译结束
var a = 123
AO{
a : 123
}
function a() {} //什么都不做,因为已经做了
全局预编译
- 生成了一个 GO 的对象 Global Object(window 就是 GO)
- 找形参和变量声明,将变量和形参名作为 GO 属性名,值为 undefined
- 在函数体里面找函数声明,值赋予函数体,没有就新增属性
console.log(a) //function a() {}
var a = 123
console.log(a) //123
function a() {}
预编译例子
先进行GO,再进行AO