预解析
在一段js代码拿过来真正一句一句运行之前,浏览器会做一些“准备工作”,就是执行上下文(预解析)
函数或者变量都会有提前解析的过程,JS会把函数或者变量提前解析一下,解析到它们对应的作用域最开始的地方
步骤:
1、先找var,function关键字以及参数
2、如果找到了var(声明的变量、参数)会给他赋一个undefined,如果找到了function,那会把整个函数都拿过来
3、把找到的东西放在对应作用域的最开始的位置
4、逐行执行代码
/*
var c=undefined
function test(){
console.log(c);
c=20;
}
*/
1 var c=10;
2 function test(){
3 console.log(c);
4 c=20;
5 }
6 test(); // 10
7 console.log(c); // 20
8 /*
9 原理:
10 1、找到了var c=undefined test(){} 整个代码块
11 2、逐行解读代码 c=10 函数test调用了
12 3、遇到一个新的代码块,找var,没有找到,逐行解读代码,console.log(c),往外找c
13 4、往下走c 被重新赋值 20
14 */
/*
var d=undefined
function test1(d){
console.log(d);
d=24;
}
*/
15 var d=12;
16 function test1(d){
17 // var d=undefined;
console.log(d); // undefined
18 d=24; // 赋值的是test1作用域内的 d
19 }
20 test1();
21 console.log(d); // 12
22 /*
23 1、找到var d=undefined
24 function test1(d){
25 console.log(d);
26 d=24;
27 } 放在作用域最开始的地方
28 2、逐行解读代码,d被赋值12,函数test1()调用,
29 有形参d,赋值var d=undefined 放在函数test1的最上面,
30 d 被赋值24,注意是test1函数里的作用域内的d,并不是外面的d,函数调用完就被释放
31 */
32 /*
var e=13;
function test2(e){
console.log(e);
e=54;
}
*/
33 var e=13;
34 function test2(e){
35 // var e=undefined;
console.log(e); // 13
36 e=54; // 更改的
37 }
38 test2(e);
39 console.log(e); // 13
40 /*
41 1、找var 跟函数
42 var e=undefined
43 function test2(e){
44 console.log(e);
45 e=54;
46 } 放在作用域的最前面
47 2、逐行解读代码 e被赋值为 13
48 函数调用,逐行走函数 test2内代码
49 函数test2代码块内预解析,有形参e,
50 e=undefined 放在函数最开始的位置
51 函数调用的时候有实参e,就是13 被传进来
52 所以console.log(e)为13 ,之后e 又被赋值为54,但注意是test2作用域内的e
53 */
函数预解析
1、函数声明
可以被预解析,可以先调用再声明
2、函数表达式
函数表达式不会被预解析,只能先声明再调用,不能先调用再声明(不然报错)
1 test(); // 不会报错
2 function test(){
3 console.log('test');
4 }
5 /*
6 函数test()被预解析放在了作用域的最前面,所以可以调用
7 */
8 test1(); // 报错 test1 为undefined, undefined() 肯定报错
9 var test1=function(){
10 console.log("test1");
11 }
12 // 找到了var test1放在了作用域最前面并被赋值 undefined ,但函数表达式的函数不会被预解析
13 // 逐行解读代码 undefined();肯定会报错
我们总结一下,在“准备工作”中完成了哪些工作:
- 变量、函数表达式——变量声明,默认赋值为undefined;
- this——赋值;
- 函数声明——赋值;
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。