JS运行三部曲
- 语法分析
- 预编译
- 解释执行
预编译要记住两点
1.函数声明整体提升
只要写一个函数声明 系统就会把该函数声明提到逻辑的最前面 无论在哪里调用 都是在函数声明后调用
//函数声明整体提升
test();//放在函数体的前面也可以执行
function test(){
document.write('a');
}
test();
输出aa
2.变量声明提升
var a=123;//这是变量的声明(var a;)+赋值(a=123;)
所以只会把var a;(变量的声明)提到前面
//变量 声明提升
document.write(a);
var a=123;
document.write(a);
注意:
window就是全局的域
1.imply global暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就为全局变量window所有
a=123;-->window.a=123;
2.一切声明的全局变量(函数里声明的是局部变量),全是window的属性
var a=123;--> window.a=123;
console.log(a);-->console.log(window.a);
function test1(){
/*赋值语句执行顺序 从右向左赋值
* 先将123赋值给b(b在这里未经声明 归window所有)
* 再声明a
* 再将b的值赋给a
* */
var a=b=123;
//console.log(a);123
//console.log(window.a);undefined
//console.log(b);123
//-->console.log(window.b);123
}
test1();
预编的过程(按顺序执行)
-
函数内的预编译:
(1.创建AO对象(Activation Object活动对象/执行期上下文)(函数产生的存储空间库)
(2.找形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined
(3.将实参值和形参统一(给形参赋传递过来的相对应的实参的值)
(4.在函数体里面找函数声明(函数声明整体提升),其值就是函数体
便于理解的范例:
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);
函数内的预编译发生在函数执行的前一刻,函数内的预编译过程如下:
1.创建AO对象
AO{}
2.找形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined
AO{
//形参
a:undefined,
//变量声明 a已经存在则不写
b:undefined
}
3.将实参值和形参统一(给形参赋传递过来的相对应的实参的值)
AO{
//形参a 和 调用函数传递的实参1统一
a:1,
b:undefined
}
4.在函数体里面找函数声明(函数声明整体提升),值赋予函数体
AO{
//有a的函数声明 将ade函数声明的值(函数体)赋给变量a
a:function a(){},
// var b=function(){}不是函数声明 而是函数表达式 不提升
b:undefined,
d:function d(){}
}
预编译完成,函数执行(解释性语言 一行一行执行)
function fn(a){
//依照AO对象里的变量 a此时是函数体 打印出function a(){}
console.log(a);
//预编译第二步 变量声明提升 var a;已经优先执行 这里只需执行a=123;的赋值方法,此时AO对象里的a变量的值变为123
var a=123;
//依照AO对象里的变量 a此时是123
console.log(a);
//预编译第四步 函数声明整体提升 该语句已经优先执行 跳过
function a(){}
//依照AO对象里的变量 a此时是123
console.log(a);
//预编译第二步 变量声明提升 var b;已经优先执行 这里只需执行b=function(){}的赋值方法,此时AO对象里的b变量的值变为function(){}
var b=function(){}
//依照AO对象里的变量 b此时是function(){}
console.log(b);
//预编译第四步 函数声明整体提升 该语句已经优先执行 跳过
function d(){}
}
//函数预编译发生在函数执行的前一刻
fn(1);
执行完后的AO对象:
AO{
a:123,
b:function (){},
d:function d(){}
}
-
全局预编译(跟函数内预编译差不多):
(1.生成一个GO对象(Global Object)也就是window对象(2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined
(3.找函数声明(函数声明整体提升),值赋予函数体
var a=123;
function a(){}
console.log(a);
console.log(window.a);
全局预编译发生在全局要执行的前一刻,全局预编译过程如下:
1.生成一个GO对象(Global Object)也就是window对象
GO{}
2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined
GO{
a:undefined
}
3.找函数声明(函数声明整体提升),值就是函数体
GO{
a:function a(){}
}
预编译完,程序执行:
//预编译第二步 变量声明提升 var a;已经优先执行 这里只需执行a=123;的赋值方法,此时GO对象里的a变量的值变为123
var a=123;
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function a(){}
//依照GO对象里的变量 a此时是123
console.log(a);
//GO就是window 就是一个对象的两个名字
console.log(window.a);
- 全局预编译和函数内预编译同时存在时,先执行全局预编译生成GO对象:
例题1:
console.log(test);
function test(test){
console.log(test);
var test=234;
console.log(test);
function test(){}
}
test(1);
var test=123;
预编译过程如下:
1.生成一个GO对象(Global Object)就是window对象
GO{}
2.找变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名作为GO属性名,值为undefined
GO{
test:undefined
}
3.找函数声明(函数声明整体提升),值就是函数体
GO{
test:function (test){
console.log(test);
var test=234;
console.log(test);
function test(){}
}
}
4.全局预编译完 程序开始执行
依照GO对象里的变量 test此时是函数体
console.log(test);
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function test(test){
console.log(test);
var test=234;
console.log(test);
function test(){}
}
//函数预编译发生在函数执行的前一刻 生成AO对象
test(1);
var test=123;
5.创建AO对象
AO{}
6.找函数内的形参和变量声明(变量声明不考虑逻辑 只要是声明就行)(变量声明提升),将变量名和形参名作为AO属性名,值为undefined
AO{
//形参
test:undefined
}
7.将实参值和形参统一
AO{
//形参a 和 调用函数传递的实参1统一
test:1
}
8.在函数体里面找函数声明(函数声明整体提升),值赋予函数体
AO{
//有a的函数声明 将a的函数声明的值(函数体)赋给变量a
test:function (){}
}
预编译完成,函数执行(解释性语言 一行一行)
function test(test){
//依照AO对象里的变量 test此时是函数体 AO GO里都有test 采用就近原则
console.log(test);
//变量声明已经优先执行 这里只执行test=234
var test=234;
//依照AO对象里的变量 test此时是234
console.log(test);
//函数声明已经优先执行 跳过
function test(){}
}
函数执行完成,程序继续执行
依照GO对象里的变量 test此时是函数体
console.log(test);
//预编译第三步 函数声明整体提升 该语句已经优先执行 跳过
function test(test){
console.log(test);
var test=234;
console.log(test);
function test(){}
}
//函数预编译发生在函数执行的前一刻 生成AO对象
test(1);
//test函数执行完成
//变量声明已经优先执行 这里只执行test=123 这里的test是GO里的test
var test=123;
程序执行完成后
GO{
test:123
}
例题2:
a = 100;
function demo(e) {
function e() {}
arguments[0] = 2;
console.log(e);
if (a) {
var b = 123;
function c() {
}
}
var c;
a = 10;
var a;
console.log(b);
f = 123;
console.log(c);
console.log(a);
}
var a;
demo(1);
console.log(a);
console.log(f);
直接写了哈
1.全局预编译
GO{
a:undefined,
demo:function(){...}
}
2.全局预编译完 程序执行
a = 100;
GO{
a:100,
demo:function(){...}
}
demo(1);//执行函数
3.函数内预编译和执行
function demo(e) {
function e() {}
//实参列表和形参有映射 arguments[0]-->e 故给AO对象里的e变量赋值2
arguments[0] = 2;
//此时AO对象里的e的值为2
console.log(e);
//此时AO对象里的a的值为undefined if语句不执行
if (a) {
var b = 123;
function c() {}
}
var c;
a = 10;
var a;
//此时AO对象里的b的值为undefined
console.log(b);
//AO对象里没有f变量的声明 故f定义在GO对象里
f = 123;
//此时AO对象里的c的值为undefined
console.log(c);
//此时AO对象里的a的值为10
console.log(a);
}
AO{
//形参1->函数体->arguments[0]映射的2
e:2,
//以下是声明的变量
b:undefined,
c:undefined,(if语句里本不能定义函数,这是个小错误)
a:10
}
GO{
a:100,
demo:function(){...},
f:123
}
4.函数执行结束 程序继续执行
//此时GO对象里的a的值为100
console.log(a);
//此时GO对象里的f的值为123
console.log(f);