首先讲预编译过程
JS代码执行过程三部曲
过程
- 语法分析:首先扫描一遍,看有没有低级的语法错误
- 预编译
- 解释执行:解释一行执行一行
预编译low讲
- 函数声明整体提升,变量 的声明提升(这个其实很low,点击low点)
假如没有预编译的话
a();
function a(){console.log("a")
}
先调用再声明,在没有预编译的情况下,不能正常输出,但是有了预编译就可以正常输出,这就是函数整体提升;
定义一个变量 var a = "1233" 这个过程叫做变量的声明 和 赋值
console.log(a); //undefined
var a = "1233"
变量 声明提升,但是赋值未被提升
low点
函数声明整体提升,变量 的声明提升 上面说的这两个点不能解释下面的代码
console.log(a);var a = "aaaa";function a(a){var a = 5;}
手动懵逼why???
真·预编译☞前奏
暗示全局变量 imply global
1.任何变量未经声明就赋值,这个变量就为全局对象(window)所拥有;
----------------------------------------------------------------------------------------------------
2.全局上声明的任何变量,即使声明了也归window 所有;window就是全局的域.
a = 1;var b = 2;
function ddd(){var a = b = 12;//赋值是从右向左,,虽然是在函数局部作用域内,12先赋值给了b,b并没声明所以b是属于window的,a是局部的,然后b在赋值给 a}ddd()
真·预编译四部曲
AO 对象中四步
预 编 译 发 生 在 函 数 执 行 的 前 一 刻
function fn(a){console.log(a);var a = 123;console.log(a);function a(){}console.log(a);var b = function () {};console.log(b);}
fn(1)
1. 创建AO对象,Activation Object (执行期上下文)
AO{ }
- 找形参和变量的声明,将变量的和形参名作为AO属性名,值为undefined
AO{a:undefined,b:undefined, }
- 将实参和形参统一
AO{a:1,b:undefined, }
- 在函数体里面,找 函数声明,值赋予 函 数 体;
AO{a:function a(){}, // 把形参覆盖了 注意:**function a(){} 是函数声明 只有它能提升; var b = function(){}这种是表达式**b:undefined, }
到此AO 对象创建完了
然后马上执行函数了 电脑从 AO 对象里面 拿东西
所以第一次打印的是function a(){},
a 被赋值123,第二次打印的是123,
然后因为function a(){}已经被提升上去,所以不用看,第三次打印也是123,
第四次打印的function ({被提升,所以最后一次打印是function(){}}
输出
// }
function test(a,b){console.log(a); //function a(){};console.log(b); //undefinedvar b = 234;console.log(b) //234a = 123;console.log(a); //123function a(){};var a ;b = 234;var b = function(){};console.log(a); //123console.log(b); //function(){};
}
test(1)
1. AO:{//过程}2. AO:{a:undefined;b:undefined;}3. AO:{a:1;b:undefined;}4. AO:{a:function a(){};b:undefined;}
所以第一次输出的a是 function a(){};b 是undefined
b=234AO:{a:function a(){};b:234;}下个b输出就是234a = 123AO:{a:123;b:234;}下个a输出就是123
===中间的声明对AO对象不产生影响所以输出不变
var b = function(){};AO:{a:123;b:function(){};}
GO 对象 global object 全局的执行上下文 === window
其实差不多
console.log(a) // 输出的 function a(){}var a = 123;
function a(){
}
console.log(a) //123
1.GO{}
2.GO{a:undefined}
3.GO{a:function a(){}}
4.GO{a:123}
GO AO 一起的
console.log(test); // 这个 输出的是 function test(){},完了之后,就该调用函数了
function test(test){console.log(test); // function test(){} 这个是自己的testvar test = 123;console.log(test); //123function test(){}
}
test(1);
var test = 123;
理解了预编译就很简单
【注】局部输出或者使用一个变量,或者方法,假如说内外部都有,优先使用内部的(局部的),局部没有才去全局找
这一点来个超级无敌简单的例子:
var global = 100;
function fn(){console.log(global) // 100;
}
fn()
很简单输出的 100过程 先来个全局 GO 对象 从上到下
GO{global:100,fn:function(){...},
}然后执行 fn 来个局部的 AOAO{// 什么都没有,么有变量和形参声明,只能去全局GO里面找global 就输出; 100}
global = 100;function fn(){console.log(global); //undefinedglobal = 200;console.log(global); //200var global = 300;console.log(global) //300}fn()var global;
function test(){console.log(b); //undefinedif(a){ //a == undefined ==>falsevar b = 100; //跳过赋值}console.log(b)undefinedc = 234;console.log(c) //234
}
var a ;
test();
a = 10;
console.log(c)
// GO{
// a:undefined;
// test:function(){...}
// }// AO{
// b:undefined, 预编译,可以跳过循环,循环语句里的变量声明已经写入了内存,所以输出是undefined
// 变量c在函数内部没有声明,就被全局接受,【参考以上知识点】
//}