1.代码分类(位置)
*全局代码
*函数(局部)代码
2.全局执行上下文
*在执行全局代码前,将window确定为全局执行上下文
*对全局数据进行预处理
*var定义的全局变量 => undefined , 添加为window的属性
*function声明的全局函数 => 赋值(fun),添加为window的方法
*this => 赋值(window)
*开始执行全局代码
//全局执行上下文
console.log(a1,window.a1); //undefined undefined
a2(); //a2()
console.log(this);
var a1 = 3 ;
function a2(){
console.log('a2()');
}
console.log(a1); //3
3.函数执行上下文
*在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象 (虚拟的,存在于栈中)
*对局部数据进行预处理
*形参变量 => 赋值(实参) => 添加为执行上下文的属性
*arguments => 赋值(实参列表), 添加为执行上下文的属性
*var定义的局部变量 => undefined , 添加为执行上下文的属性
*function声明的函数 => 赋值(fun) , 添加为执行上下文的方法
*this => 赋值(调用函数的对象)
*开始执行函数体代码
//函数执行上下文例子
function fn(a1){
console.log(a1); //2
console.log(a2); //undefined
a3(); // a3()
console.log(this); //window
console.log(arguments); // 伪数组(2,3)
var a2 = 3 ;
function a3(){
console.log('a3()');
}
}
fn(2,3);
4,*在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象(环境)
*在全局执行上下文(window)确定后,将其添加到栈中(压栈)
*在函数执行上下文创建后,将其添加到栈中(压栈)
*在当前函数执行完后,将栈顶的对象移除(出栈)
*当所有的代码执行完后,栈中只剩下window
5.测试题:
1.
function a() {}
var a ;
console.log(typeof a); //'function' ,因为先执行变量声明提升,再执行函数声明提升
2.
if(!(b in window)){
var b =1 ;
}
console.log(b); //undefined ,因为b在预处理时,就已经成为window的属性,所以没有被进行赋值为“1”的操作
3.
var c = 1;
function c(c){
console.log(c);
var c = 3;
}
c(2); //报错,因为c不是函数,原因在于在执行上下文对象中,预处理时 ,var c 先将c变量定义为undefined,然后再赋值c为“1” ,所以c不是函数;
//等价于:
var c = undefined ;
function c(c){
console.log(c);
var c = 3;
}
c = 1;
c(2);