ES6中的JS执行上下文
Posted 十九万里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6中的JS执行上下文相关的知识,希望对你有一定的参考价值。
本篇为此系列第一篇
JS执行上下文这三个概念可以说是每一个前端必须会的,但是总是学了忘记,忘了又学,立即不够深刻,之前都是用背面试题的方式去学习,今天打算深入理解一下,参考文章都放在文末。
为什么特意强调es5中呢,是因为在查阅资料中发现,其实执行上下文不同版本解释不一样的
这里我简述一下区别:
三种版本的执行上下文
ES3中的执行上下文:
在ES3中,javascript执行上下文是指在代码执行期间创建的环境
,其中包含了变量、函数、对象等信息。每个执行上下文都有一个与之关联的变量对象,用于存储该上下文中定义的变量和函数。在ES3中,执行上下文分为三种类型:
-
全局执行上下文:在代码执行之前创建,包含全局变量和函数。
-
函数执行上下文:在函数被调用时创建,包含函数参数、局部变量和函数。
-
eval执行上下文:在eval函数被调用时创建,包含eval函数中定义的变量和函数。
在ES3中,执行上下文的创建和销毁是由JavaScript引擎自动管理的
,开发者无法手动干预。同时,ES3中的执行上下文机制相对简单,没有ES6中的诸多特性,如块级作用域、let和const关键字
等。
ES5中的执行上下文:
在ES5中,执行上下文是指JavaScript代码在运行时创建的一个环境
,用于管理函数调用、变量声明、作用域链等。每个执行上下文都有一个与之关联的变量对象,用于存储该上下文中定义的变量和函数。在函数执行时,会创建一个新的执行上下文,并将其添加到执行上下文栈中。当函数执行完毕后,该执行上下文会被弹出栈,并销毁。
在ES5中,执行上下文分为三种类型:全局执行上下文、函数执行上下文和eval执行上下文。全局执行上下文是在代码执行之前创建的,而函数执行上下文和eval执行上下文是在函数调用或eval调用时创建的。在ES5中,执行上下文的创建和销毁是由JavaScript引擎自动管理的,开发者无需手动干预。
es2018的执行上下文:
在ES2018中,执行上下文被定义为一个抽象的概念,用于描述JavaScript代码在执行时的环境和状态。每当JavaScript代码开始执行时,都会创建一个新的执行上下文,并将其添加到执行上下文栈中。执行上下文栈是一个后进先出(LIFO)的数据结构,用于跟踪当前正在执行的代码的上下文。
执行上下文包含三个重要的组成部分:
-
变量环境
(Variable Environment):包含了当前执行上下文中的变量、函数声明和函数参数等信息。 -
词法环境
(Lexical Environment):与变量环境类似,但是还包含了当前执行上下文所处的词法作用域。
3. this 值
:指向当前执行上下文所属的对象。
执行上下文的创建过程可以分为两个阶段:
-
创建阶段(Creation Phase):在这个阶段,JavaScript引擎会创建变量环境、词法环境和this值,并将它们添加到执行上下文中。同时,JavaScript引擎还会扫描当前执行上下文中的代码,查找所有的函数声明和变量声明,并将它们添加到变量环境和词法环境中。
-
执行阶段(Execution Phase):在这个阶段,JavaScript引擎会按照代码的顺序执行当前执行上下文中的代码。在执行过程中,JavaScript引擎会根据需要从变量环境和词法环境中读取变量和函数,并将它们添加到当前执行上下文的作用域链中。
关于es2018的执行上下文已经有大佬写的很详细,可以看文末参考二链接。
区别:
在ES3中,执行上下文被称为“执行环境”,它是一个对象,包含了当前代码执行时所需的所有变量、函数和参数。每个函数都有自己的执行环境,当函数被调用时,它的执行环境就会被创建。
在ES5中,执行上下文被称为“执行上下文”,它是一个抽象的概念,用于描述代码执行时的环境。每个函数都有自己的执行上下文,它包含了当前函数的变量、函数和参数。在ES5中,执行上下文被分为三种类型:全局执行上下文、函数执行上下文和eval执行上下文。
在ES2018中,执行上下文被称为“词法环境”,它是一个抽象的概念,用于描述代码执行时的环境。每个函数都有自己的词法环境,它包含了当前函数的变量、函数和参数。在ES2018中,词法环境被分为两种类型:全局词法环境和函数词法环境。此外,ES2018还引入了块级作用域,每个块级作用域都有自己的词法环境。
注:下面写的是目前主流学习的执行上下文 es6版本的
一 执行上下文
1.1 概念
执行上下文是评估和执行JavaScript代码的环境的抽象概念,js代码在运行的时候都是在执行和执行上下文中运行的,
1.2 类型
一共三种执行上下文
全局执行上下文:一个程序中只有 一个 全局上下文,任何不在行数内部的代码,都属于全局上下文,也就意味着this的指向是window对象(浏览器环境下)
函数执行上下文:
函数上下文是在函数被调用的时候创建的,函数上下文可以有 很多个,调用一次函数生成一个,执行顺序是函数被调用的顺序。
Eval函数执行上下文:日常开发不会用到,是在执行eval函数内部的代码市会有自己的执行上下文。
1.3 创建执行上下文
创建时间:
-
全局执行上下文:在代码执行之前创建,它代表了全局环境,包括全局变量、函数等。
-
函数执行上下文:在函数被调用时创建,它代表了函数的环境,包括函数的参数、局部变量、内部函数等。
-
Eval 执行上下文:在 eval() 函数被调用时创建,它代表了 eval() 函数的环境,包括 eval() 函数中定义的变量、函数等。
总之,执行上下文是在代码执行之前创建
的,它们代表了代码执行时的环境,包括变量、函数、参数等
创建过程
主要有两个阶段:(1)创建阶段和(2)执行阶段
(1)创建阶段——会发生三件事情
- this值的决定,就是this绑定
- 创建词法环境组件
- 创建变量环境组件
this绑定
在全局执行上下文中,this对象指向全局对象(浏览器环境指的是window)
在函数执行上下文中,this取决于该函数是否被调用,且是被什么调用,如果是一个引用对象调用,那么this会被设置成那个对象,
如果函数没有被调用,那么此时this的值会被设置成全局对象或者underfined
(严格模式下,如果函数没有被绑定到任何对象上,函数执行上下文中的this会被设置为undefined。这是因为在这种情况下,函数没有任何上下文可依赖,因此this被设置为undefined。)
let foo =
baz: function()
console.log(this);
foo.baz(); // 'this' 引用 'foo', 因为 'baz' 被
// 对象 'foo' 调用
let bar = foo.baz;
bar(); // 'this' 指向全局 window 对象,因为
// 没有指定引用对象 如果是严格模式指向underfined
词法环境
JavaScript执行上下文中的词法环境是一个存储变量和函数的数据结构
,它与当前执行的代码块相关联。它包含了当前代码块中定义的所有变量和函数
,以及它们的作用域链
,作用域链是一个指向父级词法环境的指针,它允许代码块访问外部作用域中的变量和函数。当代码块执行完毕时,它的词法环境会被销毁,其中的变量和函数也会被释放。
重点:一种存储变量,函数,作用域链的数据结构,允许访问外部变量和函数,执行完毕后被销毁
主要由两个组件组成: 环境记录器和外部环境的引用
- 环境记录器是存储变量和函数声明的地方
- 外部环境引用是指通过作用域链可以访问父级词法环境
词法环境有两种类型:
- 全局环境(在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是
null
。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 window 对象)还有任何用户定义的全局变量,并且this
的值指向全局对象。 - 在函数环境中,函数内部用户定义的变量存储在
环境记录器
中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。
环境记录器也有两种类型(如上!):
- 声明式环境记录器存储变量、函数和参数。
- 对象环境记录器用来定义出现在全局上下文中的变量和函数的关系。
变量环境
变量环境本质上也是一个词法环境,是一个存储变量和函数的地方,它是一个JavaScript引擎在执行代码时创建的一个内部数据结构。变量环境包含了当前执行上下文中的所有变量、函数和参数,以及它们的值和引用。当JavaScript引擎执行代码时,它会根据当前执行上下文的类型创建一个对应的变量环境,以便在执行过程中能够正确地访问和操作变量和函数。在函数执行时,每个函数都会创建一个新的变量环境,用于存储该函数的局部变量和参数。在全局执行上下文中,变量环境包含了所有全局变量和函数。
那变量环境和词法环境有什么区别呢?
词法环境是指在代码*编写期间定义
的环境,它包含了当前代码所在的作用域链和变量对象
。词法环境是静态的
,一旦定义就不会改变。
变量环境是指在代码执行期间创建的
环境,它包含了当前代码执行时所需的所有变量和函数
。变量环境是动态的
,随着代码执行而改变。
因此,词法环境和变量环境的区别在于它们的创建时机和作用范围。词法环境是在代码编写期间创建的,作用范围是静态的;而变量环境是在代码执行期间创建的,作用范围是动态的。
总结
js的执行上下文整体过程:
-
创建变量对象(Variable Object):JavaScript引擎会创建一个变量对象,用于存储当前执行上下文中的变量、函数声明和形参等信息。
-
建立作用域链(Scope Chain):JavaScript引擎会建立一个作用域链,用于解析变量和函数的作用域。
-
确定this指向:JavaScript引擎会确定当前执行上下文中的this指向。
-
执行代码:JavaScript引擎会执行当前执行上下文中的代码,包括变量赋值、函数调用、条件语句、循环语句等。
-
返回执行结果:JavaScript引擎会返回执行结果,如果是函数调用,则将返回值存储在调用栈中,等待下一次执行。
代码题:
题目一:
function foo()
console.log('foo1');
foo(); // foo2
function foo()
console.log('foo2');
foo(); // foo2
// js中的代码并非一行一行执行,而是一段段执行,同时分为准备阶段和执行阶段,
// 准备阶段存在变量提升和函数提升,然后才执行,第二个foo()在准备阶段被提升了
题目二:
var message = 'global'
function foo()
console.log(message)
function bar ()
var message = 'Bar'
foo()
bar() // global
// 执行foo()的时候创建了一个新的执行上下文,会根据作用于调用message,
// 往上寻找到第一个message,也就是全局
// bar中声明的message,是在bar这个作用域内
题目三:
function f1()
console.log('听风是风');
;
f1(); //echo
function f1()
console.log('echo');
;
f1(); //echo
题目四:
var f1 = function ()
console.log('听风是风');
;
f1(); //听风是风
var f1 = function()
console.log('echo');
;
f1(); //echo
// 这两段代码的区别是上一个是函数执行栈,下一个是变量提升 但是赋值没有提升
注:在看执行上下文的题目时候重点关注解释阶段和执行阶段
参考一:# [译] 理解 JavaScript 中的执行上下文和执行栈
参考二:# ES2018 最新 【译】理解Javascript中的执行上下文和执行栈
以上是关于ES6中的JS执行上下文的主要内容,如果未能解决你的问题,请参考以下文章