深入理解执行上下文与执行上下文栈

前言:在接下来的介绍中,我们将会用到变量提升与函数提升相关的知识,不了解的同学可以自行百度,先学习下这方面的知识,也可参考我的另一篇博客进行学习。(变量提升与函数提升

一、代码分类

  根据代码所在位置进行分类,可以分为两大类:全局代码函数代码

二、全局执行上下文

1、在执行全局代码前将window确定为全局执行上下文

2、对全局数据进行预处理

 1)var定义的全局变量 => undefined, 添加为window的属性

 2)function声明的全局函数 => 赋值(fun), 添加为window的方法

 3)this => 赋值(window)

3、开始执行全局代码

  举个栗子来理解下:

  console.log(a1) //undefined
  console.log(a2) //undefined
  console.log(a3) //ƒ a3() {console.log('a3()')}
  console.log(a4) //报错:Uncaught ReferenceError: a4 is not defined
  console.log(this) //Window {window: Window, self: Window, document: document, name: "", location: Location, …}

  var a1 = 3
  var a2 = function () {
    console.log('a2()')
  }
  function a3() {
    console.log('a3()')
  }
  a4 = 4

三、函数执行上下文

1、在调用函数, 准备执行函数体之前, 创建对应的函数执行上下文对象

2、对局部数据进行预处理

 1)形参变量 => 赋值(实参) => 添加为执行上下文的属性

 2)arguments => 赋值(实参列表), 添加为执行上下文的属性

 3)var定义的局部变量 => undefined, 添加为执行上下文的属性

 4)function声明的函数 => 赋值(fun), 添加为执行上下文的方法

 5)this => 赋值(调用函数的对象)

3、开始执行函数体代码

  通过栗子来理解下:

  function fn(x, y) {
    console.log(x, y) //undefined undefined
    console.log(b1) //undefined
    console.log(b2) //ƒ b2 () {}
    console.log(arguments) //Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(this) //Window {window: Window, self: Window, document: document, name: "", location: Location, …}
    console.log(b3) //报错:Uncaught ReferenceError: b3 is not defined

    var b1 = 5
    function b2 () {
    }
    b3 = 6
  }
  fn()

四、执行上下文栈

1、在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象

2、在全局执行上下文(window)确定后, 将其添加到栈中(压栈)

3、在函数执行上下文创建后, 将其添加到栈中(压栈)

4、在当前函数执行完后,将栈顶的对象移除(出栈)

5、当所有的代码执行完后, 栈中只剩下window

  只看文字可能不太好理解,看下面的例子理解下:

                            //1. 进入全局执行上下文
  var a = 10
  var bar = function (x) {
    var b = 5
    fn(x + b)              //3. 进入fn执行上下文
  }
  var fn = function (y) {
    var c = 5
    console.log(a + c + y)
  }
  bar(10)                    //2. 进入bar函数执行上下文

执行上下栈

五、面试题

  基本概念搞懂了之后,再看道题来深入理解下:

  1. 依次输出什么?
  2. 整个过程中产生了几个执行上下文栈?
  console.log('global begin: '+ i)
  var i = 1
  foo(1);
  function foo(i) {
    if (i == 4) {
      return;
    }
    console.log('foo() begin:' + i);
    foo(i + 1);
    console.log('foo() end:' + i);
  }
  console.log('global end: ' + i)

  说明: 判断执行的过程中产生了几个执行上下栈,就看函数被调用了几次,函数调用的次数n + 1 (全局上下文栈)就是执行过程中产生的执行上下文栈。
  我们分析下上面这个例子一共被调用了几次。首先打印输出global begin: undefinedfoo(1)第一次调用时 i = 1,打印输出foo() begin:1;在函数内部有调用了自身,进行第二次调用 i= 2 ,打印输出foo() begin:2,以此类推,又在函数内部进行第三次调用 i = 3,打印输出foo() begin:4,第四次调用 i = 4 ,当进行第四次调用i = 4的时候,会直接返回。至此,调用结束,依次打印输出foo() end:3foo() end:2foo() end:1,函数执行完毕,最后打印输出global end: 1。所以执行的过程中,foo函数一共调用了4次。整个过程中共产生了5个执行上下文栈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值