javascript 变量提升和函数提升,拨开表象看内容

引言

我把变量提升和函数提升比作日食和月食。日食和月食的形成大家都知道,是由于太阳、地球、月球在运动过程中刚好在一条直线上,月亮刚好在太阳和地球之间形成日食,地球刚好在月亮和太阳之间形成月食。

我们通俗的理解月食会说月亮被天狗吃掉了,而实际是由地球、月球的运行轨迹导致的。我们通俗的理解变量提升会说,变量声明提升到它所在作用域的最开始的部分,而实际是执行上下文运行机制导致的。要想拨开变量提升和函数提升的表象看到内容,我们就需要了解一下执行上下文的过程。

一、执行上下文的2个阶段

当每次调用函数的时候都会创建一个新的执行上下文,然而,在JavaScript解释器内部,对执行上下文的每次调用都有下面的2个阶段。

1. 创建阶段

当函数被调用,在执行里边的代码之前

  • 创建作用域链
  • 创建参数、变量和函数
  • 确定this的值创建完成的执行上下文对象,表示为:
executionContextObj = {
    'scopeChain': { /* variableObject + all parent execution context's variableObject */ },
    'variableObject': { /* function arguments / parameters, inner variable and function declarations */ },
    'this': {}
}
2. 代码执行阶段:

赋值,函数的引用以及解析/执行代码

二、创建阶段的详细过程

  1. 初始化作用链
  2. 创建variableObject
  • (1) 创建arguments对象,检查传入的参数,初始化名称和值,并且创建一个引用的副本
  • (2) 扫描上下文中的函数声明
    • 每找到一个函数,就以函数名在variableObject中创建一个属性,属性指向函数的内存空间
    • 如果variableObject中存在函数名称的属性,则属性的引用值会被覆盖
  • (3) 扫描上下文中的变量声明
    • 每找到一个变量,就以变量名在variableObject中创建一个属性,属性值初始化为undefined
    • 如果variableObject中存在变量名称的属性,不做处理,继续扫描
  1. 确定上下文中this的值

!理解变量提升和函数提升,扫描上下文中的函数声明和扫描上下文中的变量声明的过程是关键

三、举个例子

下面是很常见的一道面试题:

var a =123;  
function f() {  
    console.log(a); 
    console.log(b); 
    var a = 1;  
    var b = 2;
    function a () {}
}  
f(); 
  • 当执行方法f的时候会创建一个执行上下文对象,这时executionContextObj为一个空对象
executionContextObj = {}
  • 然后进入到创建阶段,上述第(1)步,由于没有参数,executionContextObj创建一个空的arguments数组
executionContextObj = {
    arguments: []
}
  • 接着执行第(2)步,扫描上下文中函数的声明, 找到了函数 function a () {}, 在variableObject中增加属性a, 值为a函数
executionContextObj = {
    arguments: [],
    variableObject: {
        a: function a () {}
    }
}
  • 再执行第(3)步,扫描上下文中变量的声明,找到了变量a和变量b, 由于variableObject中已经有a属性了,不做处理;没有b属性,在variableObject中增加属性b, 值为undefined
executionContextObj = {
    arguments: [],
    variableObject: {
        a: function a () {},
        b: undefined
    }
}
  • 再确定this值为window,创建阶段结束
executionContextObj = {
    arguments: [],
    variableObject: {
        a: function a () {},
        b: undefined
    },
    this: window
}
  • 最后执行代码
    1. 输出a的值为:function a () {}
    2. 输出b的值为:undefined
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值