JS高级:执行上下文和执行上下文栈

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44627407/article/details/102701654

1.变量提升和函数提升

通过var声明的变量可以变量提升,提升的值为undefined
通过函数声明的定义的函数可以函数提升,提升的值是整个函数,而通过函数表达式定义的函数不能函数提升,以为其本质是变量,提升的结果是undefined,所以声明前调用时出错。
栗1:–变量提升(举例子来说明变量提升更清晰简洁)

    var a = 3
    function fn() {
      console.log(a)
      var a =4
    }
   fn() // undefined
   //函数fn相当于
   function fn() {
     var a // 此时a值为undefined
     console.log(a) // 由于作用域的原因,它自身有a变量,所以不会再向上(到全局中)去找该变量
     a =4
   }

栗2:–函数提升

   fn2() // fn2 --函数提升
   fn3() // 报错
   function fn2() {
     console.log( 'fn2')
   }
   var fn3 = function () {
     console.log( 'fn2')
   }

Q:变量提升和函数提升是如何产生的?

2.执行上下文(并不真实存在)

2.1 代码分类(按位置来分)
全局代码
局部(函数)代码
2.2 全局执行上下文
在执行全局代码之前,将window作为全局上下文,JS引擎会做以下三步准备(预处理):
a。 将全局中使用var定义的的变量放到window中,作为window的属性,并赋值undefined ——变量提升的原因
b。 将全局中使用函数声明定义的函数,整个函数放到window中,作为window的方法——函数提升的原因
(变量提升在函数提升前面执行,所以有函数名和变量名冲突时,函数提升会覆盖变量提升)
c。 指定全局的this ——此时值为window
(注意:例如,c = 2这个语句在执行全局代码前,window(全局执行上下文)中并不会包含c,而是等到执行到该语句时c才存在)

栗子:

console.log(a1) // undefined ——调用前window中已经存在变量a1
// 相当于console.log(window.a1)
a2() // a2 ——调用前window中已经存在函数a2
// window.a2()
console.log(this) // window ——此时全局环境的this为window
var a1 = 3
function a2() {
  console.log('a2')
}

2.3 函数执行上下文(并不真实存在)
函数调用前,提前生成函数执行向下文,JS引擎会做以下准备(预处理):
a。 将函数中的使用var定义的变量放到函数执行上下文中,作为执行上下文的属性,并赋值undefined
b。 将由实参传给形参的整个arguments对象放到执行上下文中,作为执行上下文的属性
(变量提升在函数提升前面执行,所以有函数名和变量名冲突时,函数提升会覆盖变量提升)
c。 将函数内部使用函数声明定义(使用function定义)的函数,整个放到执行上下文中,作为执行上下文的方法
d。 指定该函数的this值,该值指向本函数的调用者
做好以上准备后才开始执行函数
栗子:

 function fn(a1) {
    console.log(a1) // 1
    console.log(a2) // 3
    a3() // I am a3
    console.log(arguments) // (1,2,3)-伪数组
    console.log(this) // window
    var a2 = 3
    function a3() {
      console.log('I am a3')
    }
  }
 fn(1,2,3) // 1 3  I am a3  (1,2,3,...)-伪数组 window

3.执行上下文栈(栈–后进先出)

(执行上下文栈——管理和保存所有的执行上下文

全局函数执行时,js引擎首先将window放到栈底 ——>
每调用一个函数,都会把函数推入栈内 ——>
函数执行结束就从栈顶弹出(释放函数所占的内存)(永远是栈顶那个的函数在执行) ——>
所有函数执行结束后,栈中最终只剩下window

   var a = 10
   var fn = function (x) {
     var b = 5
     foo(x + b) // 函数中可以访问全局中的属性和方法
   }
   var foo = function (y) { // foo()是全局变量(函数)
     var c =5
     console.log(a + c + y)
   }
   fn(10) // 30
    // 以上例子产生三个执行上下文:全局上下文(永远在栈底)、fn执行上下文、foo执行上下文
    // 执行上下文栈结构变化:1.(栈底)window ==>2.(栈底)window --> fn() ==>3.(栈底)window--> fn()--> foo(栈顶) ==>4. (栈底)window --> fn() ==> 5.(栈底)window

4.执行上下文和执行上下文栈相关面试题

题目1:
输出结果的顺序?-- undefined 1 2 3 3 2 1 1
整个过程产生的执行上下文一共有几个?5个–window、foo(1)、foo(2)、foo(3)、foo(4)

  console.log(i) // undefined
  var i = 1
  foo(1)
  function foo(i) {
    if (i === 4) { // 递归终止条件
      return
    }
    console.log(i)
    foo(i + 1) // 递归调用
    console.log(i)
  }
  console.log(i) // 1

分析:

foo(1)
  function foo(i) {
   if (i === 4) { // 递归终止条件
     return
   }
     console.log(i)
     foo(i + 1) // 递归调用
     console.log(i)
  }
  // 相当于
  foo(1){
   if (i === 4) { // 递归终止条件
     return
   }
   console.log(1) // 1
   foo (2){
     if (i === 4) { // 递归终止条件
       return
     }
     console.log(2) // 2
     foo(3){
       if (i === 4) { // 递归终止条件
         return
       }
       console.log(3) // 3
       foo(4){
         if (i === 4) { // 递归终止条件
           return
         }
       }
     }
     console.log(3)//3
   }
   console.log(2) //2
 }
console.log(1) // 1

题目2:

 function a() {
   }
  var a
  console.log(typeof a) 
  // function ——先执行变量提升,再执行函数提升,函数提升把变量提升覆盖了

题目3:

 if (!(b in window)){
    var b = 1
  }
 console.log(b) // undefined ——调用b时,window中没有b,所以if语句都没有被执行

题目4:

  var c = 1
  function c(c) {
    console.log(c)
  }
  c(2) //报错

分析:

  //执行过程相当于
  var c // 变量提升
  function c() { // 函数提升,在执行时不会在执行函数这个代码块
    console.log(c)
  }
  c = 1 // 正式执行时,c并不是函数
  c(2// 执行时出错,因为c不是函数

猜你喜欢

转载自blog.csdn.net/weixin_44627407/article/details/102701654
今日推荐