谈谈javascript中的变量提升还有函数提升

在很多面试题中,经常会看到关于变量提升,还有函数提升的题目,所以我就写一篇自己理解之后的随笔,方便之后的查阅和复习。

首先举个例子

foo();//undefined
function foo(){
    console.log(a);//undefined
    var a = 10;
}

上面的例子中,foo()函数的声明在调用之后,但是还是会输出函数中的结果。在foo()函数的内部,变量a的声明之前就调用了,但是系统会输出undefined,而不会报错,这里面就涉及到了变量提升还有函数提升,为什么会出现这样的情况呢,先来了解几个重要的概念,就可以解开这个谜底了。

一、什么是执行上下文

每次当控制器转到可执行代码的时候,就会进入一个可执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。

一个执行上下文的生命周期

执行上下文.PNG
从图中可以看出,一个执行上下文的生命周期包括创建执行两个阶段。
1、第一个阶段中做的工作有:

  • 生成变量对象
  • 建立作用域链
  • 确定this的指向

2、第二个阶段中做的工作有:

  • 变量赋值
  • 函数引用
  • 执行其他代码

到这里还不能解析为什么会有变量提升和函数提升的过程,那么我们接下来再深入执行上下文中的创建阶段中的生成变量对象的过程

什么是变量对象

在很多面试题中,会考到变量对象和活动对象的区别,其实活动对象和变量对象是同一个对象,只是处于执行上下文的不同生命周期而已,活动对象处于执行阶段。

变量对象.PNG

从图中可以看出,在生成变量对象的过程中,执行的操作有三步
1、创建arguments对象
2、检查functfen函数声明创建属性
3、检查var变量声明创建属性

所以在了解完执行上下文和变量对象后,就可以分析一下我们的问题了。
当我们执行第一句话的时候foo(),javascript引擎会创建一个执行上下文testEc,并且生成一个变量对象VO,首先创建argument对象,然后检查function函数声明并且创建一个属性,所以就生成了如下的vo对象
创建过程
testEC = {
    // 变量对象
    VO: {},
    scopeChain: {},
    this: {}
}

// 因为本文暂时不详细解释作用域链和this,所以把变量对象专门提出来说明

// VO 为 Variable Object的缩写,即变量对象
VO = {
    arguments: {...},  //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解,我做了这样的处理
    foo: <foo reference>  // 表示foo的地址引用
    a: undefined
}
变量提升也是同样的道理。
posted @ 2017-03-29 16:22  McRay  阅读(232)  评论(0编辑  收藏  举报