JS—执行上下文和作用域

执行上下文

每一个上下文都有一个相关联的变量对象(variable object),在这个上下文中定义的所以函数和变量都存在这个对象上。上下文再其所有代码执行完成后会被销毁,包括定义在上面的所有函数和变量(全局上下文在应用程序退出才会被销毁,比如关闭网页和浏览器)。执行上下文会在执行时候创建。

全局上下文

就是window对象,对全局数据进行预处理

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

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

this==>赋值(window)

开始执行全局代码

函数上下文

在调用函数, 准备执行函数体之前, 创建对应的函数上下文对象(虚拟的, 存在于栈中)

对局部数据进行预处理

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

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

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

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

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

开始执行函数体代码

执行上下文栈

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

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

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

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

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

console.log('gb: '+ i)
  var i = 1
  foo(1)
  function foo(i) {
    if (i == 4) {
      return
    }
    console.log('fb:' + i)
    foo(i + 1) //递归调用: 在函数内部调用自己
    console.log('fe:' + i)
  }
  console.log('ge: ' + i)

两个问题:

 1.依次输出什么?

          gb: undefined

          fb: 1

          fb: 2

          fb: 3

          fe: 3

          fe: 2

          fe: 1

          ge: 1

2. 整个过程中产生了几个执行上下文?  5个(递归函数执行一次就会产生一个)

下面再看一些例子:

1.先执行变量提升, 再执行函数提升?

 function a() {}
  var a
  console.log(typeof a) // 'function'

 函数提升的优先级大于变量提升

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

 为什么会报错?此时C并不是函数(Uncaught TypeError: c is not a function)

记住一句话:函数提升的优先级大于变量提升,且不会被同名变量声明所覆盖,但是同名变量赋值后会被覆盖

作用域

如何理解?其实就是代码段所管理的区域,它是静态的(相对于上下文对象,上下文是执行时候才会确定), 在编写代码时就确定了 。作用是隔离变量,不同作用域下同名变量不会有冲突。分为全局作用域和函数作用域 。

作用域和上下文的区别与联系:

1. 区别1

全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经确定了。而不是在函数调用时

 

全局上下文环境(这是一个对象)是在全局作用域确定之后, js代码马上执行之前创建

函数上下文是在调用函数时, 函数体代码执行之前创建

2. 区别2

作用域是静态的, 只要函数定义好了就一直存在, 且不会再变化

上下文是动态的, 调用函数时创建, 函数调用结束时就会自动释放

3. 联系

上下文环境(对象)是从属于所在的作用域

全局上下文环境==>全局作用域

函数上下文环境==>对应的函数使用域

看一个例子: 

 var a = 10,
    b = 20
  function fn(x) {
    var a = 100,
      c = 300;
    console.log('fn()', a, b, c, x)
    function bar(x) {
      var a = 1000,
        d = 400
      console.log('bar()', a, b, c, d, x)
    }

    bar(100)
    bar(200)
  }
  fn(10)

 

作用域链

函数作用域链:函数先在自身找变量,找不到时,就会找函数的父函数,父函数中没有就找爷爷函数,以此类推,直到找到window全局作用域。如果都没有只能报错了。

看一个例子: 

 var a = 1
  function fn1() {
    var b = 2
    function fn2() {
      var c = 3
      console.log(c)
      console.log(b)
      console.log(a)
      console.log(d)
    }
    fn2()
  }
  fn1()

d找不到就会报错!!!下面再看一些例子:为什么报错呢?

因为在匿名函数作用域中没有fn2变量,会向外层作用域找(全局作用域),依然没有找到,就会报错。上面函数表达式,window对象上会有fn函数,所以执行fn时,在全局上下文中能找到fn。

目录

执行上下文

全局上下文

函数上下文

执行上下文栈

作用域

作用域链


var fn = function () {
    console.log(fn)
  }
  fn()

  var obj = {
    fn2: function () {
     console.log(fn2)//报错,因为在函数体内没有fn2变量,如果要访问fn2属性,必须加this关键字
     //console.log(this.fn2)
    }
  }
  obj.fn2()

 下面为什么输出是10?当函数定义好了,作用域就已经固定了,有三个作用域:全局作用域,fn函数作用域和show函数作用域。其实将fn函数作为参数传入就相当于执行fn函数,fn执行时会向外层作用域找是否有x变量。

 var x = 10;
  function fn() {
    console.log(x);
  }
  function show(f) {
    var x = 20;
    f();
  }
  show(fn);//10

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值