执行上下文的生命周期
大致分为两个阶段
创建阶段
在这个阶段,执行上下文会分别创建变量对象,确认作用域链,以及确定this的指向
执行阶段
完成变量赋值,函数引用,以及执行其他代码
变量对象(VO)
JavaScript代码中声明的所有变量都保存在变量对象中,除此之外,变量对象还可能包含以下内容
- 函数的说有参数(Firefox中为参数对象arguments)
- 当前上下文的所有函数声明(通过function声明的函数)
- 当前上下文中所有变量声明(通过var声明的变量)
变量对象的创建过程
- 函数的参数变量及其值
- 依次获取当前上下文中所有的函数声明,例如: foo:<foo reference>
- 依次获取当前上下文中的变量声明(通过var声明的变量),属性值会先被赋值为undefined,如果该变量名跟函数名一样,那么为了防止同名的函数被修改为undefined,则会跳过,原属性值不会被修改.(let/const是在执行上下文执行阶段开始执行的,避免了变量提升带来的影响)
实例分析
基于全局上下文分析
//=========
//demo1.js
var a = 30
//第一步
var a = undefined
//第二步
a = 30
//=========
//=========start====
//demo2.js
var a = 20
function fn(){console.log('fn')}
function fn(){console.log('cover fn')}
function a() {console.log('cover a')}
console.log(a)
fn()
var fn = 'I want cover function named fn.'
console.log(fn)
//=========
// 函数的声明优先级高于变量的声明
// 同名函数会覆盖函数与变量
// 同名变量不会覆盖函数
//创建阶段,声明
function fn(){console.log('fn')}
function fn(){console.log('cover fn')}
function a() {console.log('cover a')}
var a = undefined
var fn = undefined
//创建阶段,按代码顺序进行赋值和函数的调用
a = 20
console.log(a) // 20
fn() //cover fn
fn = 'I want cover function named fn.'
console.log(fn) //'I want cover function named fn.'
//=========end====
基于函数上下文分析
//demo1.js
function test(){
console.log(a)
console.log(foo())
var a = 1
function foo(){
return 2
}
}
test()
//创建过程
testEC = {
vo:{}//变量对象
scopeChain:[]//作用域链
this:{}
}
//就看该函数的执行上下文的VO的创建
Vo = {
arguments:{...},
foo:<foo reference>,
a:undefined
}
//执行阶段,活动对象AO,AO还包含了this的指向,所有你在函数中使用箭头函数的时候,this的指向也是通过这里确定
VO=>AO = {
arguments:{...},
foo:<foo reference>,
a:undefined,
this:window
}
全局上下文的变量对象
每种语言总有一些普通奇奇怪怪的东西,例如:Java不支持多继承,偏偏默认继承Object对象
windowEC = {
vo:window,
scopeChain:{},
this:window
}