javascript执行上下文的过程是什么

发布时间:2023-05-04 11:44:37 作者:zzz
来源:亿速云 阅读:119

这篇文章主要介绍“javascript执行上下文的过程是什么”,在日常操作中,相信很多人在javascript执行上下文的过程是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”javascript执行上下文的过程是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

简介

执行上下文可以说是js代码执行的一个环境,存放了代码执行所需的变量,变量查找的作用域链规则以及this指向等。同时,它也是js很底层的东西,很多的问题如变量提升、作用域链和闭包等都可以在执行上下文中找到答案,所以这也是我们学习执行上下文的原因

执行上下文分为三种:

因为执行上下文是在编译阶段创建的,所以接下来先看一下js代码的执行过程吧

javascript代码的执行过程

一段js代码的执行过程中,先是会进行编译阶段,js引擎会将代码进行编译,再进入执行阶段

也就是说,js代码是按照“段”来执行的,具体就是全局代码就是一段代码,函数执行也算一段代码,编译也是按照“段”来编译的,也就是一整个js代码会出现多个编译阶段

编译阶段

编译阶段是一个很复杂的过程,这里只是简单的介绍:

1、编译阶段完成两件事情:创建执行上下文和生成可执行代码

2、执行上下文就包括变量环境和词法环境和this指向等,创建执行上下文的过程:

3、接着,js引擎就会把其他的代码编译为字节码,生成可执行代码

编译阶段完成后,js引擎开始执行可执行代码,按照顺序一行一行执行,当遇到函数或者变量时,会在变量环境中寻找,找不到的话就会报错

如果遇到赋值语句时,就会将值赋值给变量

var变量提升与let和const

变量提升是指在js代码执行过程中,js引擎把变量的声明部分和函数声明部分提升到代码开头的“行为”。变量被提升后,会给变量设置默认值undefined

变量提升的实现并不是物理地移动代码的位置,而是在编译阶段被js引擎放入内存中。

1、普通变量提升会赋值为undefined,函数变量名会将整个函数提升

console.log(fn);  // [Function: fn]
console.log(a);  // undefined
function fn() {
    console.log(111);
}
var a = 1

2、函数表达式只会将变量提升,不会将函数题提升

3、当有多个相同类型的声明(同样是函数声明或者同样是普通变量声明),最后一个声明会覆盖之前的声明

4、当函数声明与变量声明同时出现时,函数声明优先级更高

当然,变量提升有很多的缺陷,所以从es6开始引入了let和const关键字,通过let和const声明的变量不具有变量提升特性,同时也支持块级作用域,先看一下作用域吧

作用域

作用域其实就是一套定义函数调用和变量使用的规则,其中,就有三种作用域:

通过var声明的变量没有块级作用域,通过const let声明的变量有块级作用域

那js是如何var的变量提升和支持块级作用域的呢?这就得从执行上下文的角度说起

编译阶段生成执行上下文:

假设js需要执行一个函数

接下来看一段代码:

function foo(){
    var a = 1
    let b = 2
    {
      let b = 3
      var c = 4
      let d = 5
      console.log(a)
      console.log(b)
    }
    console.log(b) 
    console.log(c)
    console.log(d)
}   
foo()

当执行到代码块时,对应的执行上下文如下:

foo函数执行上
变量环境
a = 1, c = 3
词法环境
{b = 3, d = 5}
{b = 2}

当代码块的代码执行完毕后,对应的词法环境里的变量就会被弹出栈

foo函数执行上下文
变量环境
a = 1, c = 3
词法环境
{b = 2}

原因

通过上面的分析,我们可以总结变量提升和块级作用域的实现:

单个执行上下文中变量的查找规则

沿着词法环境的栈顶向下查询,如果在词法环境的某个快中查找到了,就直接返回给js引擎,如果没有找到,就继续在变量环境中查找


javascript执行上下文的过程是什么

调用栈

调用栈是用来管理函数调用关系的一种栈结构

在函数调用之前,会创建对应的执行上下文,并生成对应的可执行代码

作用域链

词法作用域

词法作用域指的是作用域有代码中函数的声明位置决定的,也叫做静态作用域

也就是说,当创建一个执行上下文的时候,其内部的outer就会根据词法作用域去执行对应的外部执行上下文

在外部的执行上下文中查找时,也是先从词法环境中开始

function fn() {
    console.log(a);
}
function fn1() {
    let a = 1
    fn()
}
let a = 3  // let声明的变量是在词法环境中的
fn1()  // 3

闭包

在js中,根据词法作用域的规则,内部函数总是可以访问外部函数中声明的变量,当通过调用一个外部函数返回一个内部函数后,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包

function foo() {
    var myName = " 极客时间 "
    let test1 = 1
    const test2 = 2
    var innerBar = {
        getName:function(){
            console.log(test1)
            return myName
        },
        setName:function(newName){
            myName = newName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName(" 极客邦 ")
bar.getName()
console.log(bar.getName())

上面代码中,由于存在闭包现象,foo函数执行结束后,内部的变量还会被保存,调用栈如下图:

javascript执行上下文的过程是什么

当执行到 bar.setName 方法中的myName = "极客邦"这句代码时,JavaScript 引擎会沿着“当前执行上下文–>foo 函数闭包–> 全局执行上下文”的顺序来查找 myName 变量,你可以参考下面的调用栈状态图:

javascript执行上下文的过程是什么

闭包的回收

var bar = {
    myName:"time.geekbang.com",
    printName: function () {
        console.log(myName)
    }    
}
function foo() {
    let myName = " 极客时间 "
    return bar.printName
}
let myName = " 极客邦 "
let _printName = foo()
_printName()
bar.printName()

从上下文角度讲this

执行上下文分为三种,对应的this也只有三种:全局上下文的this,函数中的this,eval中的this

到此,关于“javascript执行上下文的过程是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. JavaScript数组对象去重的方法有哪些
  2. Javascript promise异步编程怎么使用

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript

上一篇:Java中的Synchronized原理是什么

下一篇:java字符串遍历的常用方法是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》