执行上下文的生命周期



    大致分为两个阶段



    创建阶段

            在这个阶段,执行上下文会分别创建变量对象,确认作用域链,以及确定this的指向



    执行阶段

            完成变量赋值,函数引用,以及执行其他代码



变量对象(VO)

    JavaScript代码中声明的所有变量都保存在变量对象中,除此之外,变量对象还可能包含以下内容

  • 函数的说有参数(Firefox中为参数对象arguments)
  • 当前上下文的所有函数声明(通过function声明的函数)
  • 当前上下文中所有变量声明(通过var声明的变量)


    变量对象的创建过程

  1. 函数的参数变量及其值
  2. 依次获取当前上下文中所有的函数声明,例如: foo:<foo reference>
  3. 依次获取当前上下文中的变量声明(通过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
}