变量提升和函数提升

通过var定义(声明)的变量,在定义语句之前就可以访问到。但是其值为undefined
通过function声明的函数,在之前就可以直接调用
:函数定义(对象)

var a=3
function fn(){
  console.log(a)
  var a=4
}
fn()
// 这里输出的是undefined,因为在定义语句之前就可访问。 变量提升

fn2()
function fn2(){
  console.log('fn2()')
}
//在定义之前就可以调用 函数提升

fn3()
var fn3=function(){
  console.log('fn3()')
}
//这里的fn3()并不能调用,因为这是变量提升

全局执行上下文

.在执行全局代码前将window确定为全局执行上下文
.对全局数据进行预处理
​ 1.var定义的全局变量==>undefined,添加为window属性
​ 2.function声明的全局函数==>赋值(fun),添加为window的方法
​ 3.this==>赋值(window)
.开始执行全局代码

函数执行上下文

.在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)
.对局部数据进行预处理
​ 1.形参变量==>赋值(实参)>添加为执行上下文的属性
​ 2.arguments
>赋值(实参列表),添加为执行上下文的属性
​ 3.var定义的局部变量==>undefined,添加为执行上下文的属性
​ 4.function声明的函数==>赋值,添加为执行上下文的方法
​ 5.this==>调用函数的对象
.开始执行函数体的代码

执行上下文栈

1.在全局代码执行前,js引擎会创建一个栈来存储管理所有的上下文对象
2.在全局执行上下文(window)确定后,将其添加到栈中(压栈)
3.在函数执行上下文创建后,将其添加到栈中(压栈)
4.在当前函数执行完后,将栈顶的对象移除(出栈)
5.当所有的代码执行完后,栈中只剩下window
26

补充

先执行变量提升,再执行函数提升。

function a(){}
var a
console.log(typeof a)  //return 'function'
//因为先执行变量提升,后执行函数提升。所以a被定义为函数

var c=1
function c(c){
​	console.log(c)
​	var c=3
}
c(2) //报错
//因为函数提升和变量提升,所以在c赋值之前已经执行过function,
//在c(2)执行前c的实际值为c=1,所以此时c不是函数,会报错。我们可以等效为以下代码

var c
function c(c){
​	console.log(c)
​	var c=3
}
c=1
c(2) 

Q.E.D.