JS执行上下文和作用域、作用域链

302 阅读4分钟

执行上下文

js引擎内部有一个执行上下文栈(Excution Context Stack,简称ECS),它是用于执行代码的调用栈。 全局代码块最先执行

  • 全局代码块为了执行会创建一个Global Execution Context(GEC);
  • GEC被放到ECS中执行,分为两部分
    • 第一部分:代码执行前,解析器parser转成AST的过程中,会将全局变量、函数等加入到GlobalObject中,但是并不会赋值,这个过程也叫做变量提升
    • 第二部分:在代码执行时会对变量赋值,或者是执行其它函数。

对第一部分进行总结:

  • 创建执行上下文,压入执行上下文栈
  • 解析器对代码进行解析,对变量进行提升(函数提升先于变量提升),函数会开辟新的堆空间(为了函数可以在定义前调用)
  • 执行上下文关联VO(全局代码的VO是GO)、this、作用域链。
var num1=10

        var num2=100

        function fn(){

            var message='hello'

            console.log('fn被调用');

        }

        var num3=200

图片.png 第二部分总结:

  • 变量赋值从上往下
  • 执行代码时不会再对函数进行赋值,因为在执行前的解析代码的过程中就已经创建了一个函数对象了
  • 遇到函数调用,创建一个函数执行上下文压入执行上下文栈

图片.png 函数执行上下文
当全局代码执行到函数调用时,会将一个函数上下文压入执行上下文栈,同时开辟新的堆空间创建一个函数的vo对象:Activation Object(AO),对象保存着函数里进行变量提升的属性和方法,接着将AO与执行上下文关联,开始执行代码,代码执行完毕后会将次函数上下文弹出执行上下文栈。

图片.png

一段代码的执行过程:

图片.png arguments是一个对象,保存函数传进去的参数的值。
bar()函数执行完毕后会将相应的上下文执行栈出栈,继续执行栈顶的代码,执行完又出栈,执行全局代码。

作用域的定义

JavaScript中作用域一般指的是变量和函数的可访问性和可见性范围,或者说是某个变量或函数生效的区域。在JavaScript中,作用域主要分为两种:全局作用域和局部作用域,es6中又定义了块级作用域。

  • 全局作用域:全局作用域是指在全局范围内声明的变量和函数,它们可以在代码的任何位置被访问。在JavaScript中,全局作用域通常是指在全局作用域下声明的变量和函数,它们可以被整个程序所访问。
  • 局部作用域:局部作用域是指声明在函数内部的变量和函数,在函数执行时只能在函数内部被访问。在JavaScript中,每当调用一个函数时,都会创建一个新的局部作用域。这个局部作用域只在函数执行期间存在,函数执行结束后,局部作用域就会被销毁,里面的变量和函数也会消失。
  • 块级作用域: 在JavaScript中,作用域是通过作用域链来实现的。当一个变量或函数在某一个作用域中被访问时,JavaScript引擎会先从当前作用域中查找该变量或函数,如果找不到就会沿着作用域链向上层作用域查找,直到找到为止。如果到全局作用域都没找到,那么该变量或函数就会被认为是未定义的(undefined)。

在JavaScript中,作用域是由函数定义时决定的,而不是函数调用时。即使函数在后面的代码里调用,它定义时的作用域也不会改变。这种行为称为词法作用域。

作用域链(scope chain)

  • 作用域链是一个对象列表,用于变量标识符的求值 当进入执行上下文时,作用域链就会被创建,并且根据代码类型,添加一系列的对象

图片.png

函数多层嵌套作用域链

图片.png