js执行上下文

1.什么是执行上下文

JavaScript是一个单线程语言,意味着同一时间只能执行一个任务。当JavaScript解释器初始化执行代码时, 它首先默认进入全局执行环境(execution context),从此刻开始,函数的每次调用都会创建一个新的执行环境。

2.执行环境的分类

  • 全局环境——JavaScript代码运行时首次进入的环境。
  • 函数环境——当函数被调用时,会进入当前函数中执行代码。
  • Eval——eval内部的文本被执行时(因为eval不被鼓励使用,此处不做详细介绍)。

3.执行上下文栈

概念

当JavaScript代码执行的时候,会进入不同的执行上下文,这些执行上下文会构成了一个执行上下文栈(Execution context stack,ECS)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。

代码在执行过程时遇到以上三种执行环境的代码时,都会生成一个对应的执行上下文,压入执行上下文栈中,当栈顶的上下文执行完毕之后,会自动出栈。下面用一个例子说明,可参考上面的执行环境栈图片

var a = 1;
function fn1() {
  function fn2() {
   console.log(a);
 }
 fn2();
}
fn1();

第一步,全局执行上下文入栈。

第二步,遇到fn1(),执行代码,创建自己的执行上下文,入栈。

第三步,fn1的上下文入栈之后,接着执行其中的代码,遇到fn2(),创建自己的执行上下文,入栈。

第四步,在fn2的执行上下文中未创建新的执行上下文,代码执行完毕之后,fn2的执行上下文出栈。

第五步,fn2的执行上下文出栈之后,继续执行fn1的可执行代码,也未创建新的执行上下文,出栈。这个时候栈中只剩下全局执行上下文了。

有5个需要记住的关键点,关于执行栈(调用栈):

  • 单线程。
  • 同步执行。所有的执行上下文都得等到栈顶的执行之后才能顺序执行
  • 只有一个全局执行上下文。
  • 函数上下文是无限制的。
  • 每次函数被调用时都会创建新的执行上下文,包括调用自己

3.执行上下文的构成

三个重要的属性,变量对象(Variable object,VO),作用域链(Scope chain)和this。这三个属性跟代码运行的行为有很重要的关系

变量对象(Variable object)

变量对象(缩写为VO)是一个与执行上下文相关的特殊对象

变量对象是与执行上下文相关的数据作用域。它是一个与上下文相关的特殊对象,其中存储了在上下文中定义的变量和函数声明。也就是说,一般VO中会包含以下信息:

  • 变量 (var, Variable Declaration);
  • 函数声明 (Function Declaration, FD);
  • 函数的形参

在JavaScript解释器内部,每次调用执行上下文,分为两个阶段:

创建阶段(此时函数被调用,但未执行内部代码):

  • 设置[[Scope]]属性的值
  • 设置变量对象VO,创建变量,函数和参数。
  • 设置this的值。

激活/代码执行阶段:

在当前上下文上运行/解释函数代码,并随着代码一行行执行指派变量的值和函数的引用。

创建阶段

1.根据函数的参数,创建并初始化arguments object。

2.扫描上下文的函数声明:对于找到的函数声明,将函数名和函数引用存入VO中,如果VO中已经有同名函数,那么就进行覆盖。

3.扫面上下文的变量声明:对于找到的每个变量声明,将变量名存入VO中,并且将变量的值初始化为undefined。如果变量的名字已经在变量对象里存在,不会进行任何操作并继续扫描。

要记住:函数扫描是在变量之前。

4.提升(Hoisting)

(function() {
    console.log(typeof name); // function
    console.log(typeof another); // undefined
    var name = ‘Abby‘,
        another = function() {
            return ‘Lucky‘;
        };
    function name() {
        return ‘Abby‘;
    }
    console.log(typeof name); // string
    console.log(typeof another); // function
}())

此时的创建阶段的过程是:

1.函数name和其引用被存入到VO之中。

2.变量name发现在VO之中存在同名的属性,因此忽略。

3.变量another存入到VO之中,并赋值为undefined。(这也是函数表达式不会提升的原因)

此时代码从上到下执行的时候激活阶段的过程是:

1.console.log(typeof name); 此时name在VO中是函数。

2.console.log(typeof another); 此时another在VO中的值是undefined。

3.指出函数name的引用。

4.将name赋值为’Abby’。

5.将another赋值为函数表达式的值。

6.console.log(typeof name); 此时的name由于被函数被字符串赋值覆盖因此是string类型。

7.console.log(typeof another); 此时的another被赋值成函数表达式因此是function类型。

因此理解执行上下文之后也就很好理解了为什么我们能在name声明之前访问它,为什么之后的name的类型值发生了变化,为什么another第一次打印的时候是undefined等等问题了。

5.小结

当javascript代码被浏览器载入后,默认最先进入的是一个全局执行环境。当在全局执行环境中调用执行一个函数时,程序流就进入该被调用函数内,此时JS引擎就会为该函数创建一个新的执行环境,并且将其压入到执行环境堆栈的顶部。浏览器总是执行当前在堆栈顶部的执行环境,一旦执行完毕,该执行环境就会从堆栈顶部被弹出,然后,进入其下的执行环境执行代码。这样,堆栈中的执行环境就会被依次执行并且弹出堆栈,直到回到全局执行环境。

原文地址:https://www.cnblogs.com/yu-hailong/p/8638868.html

时间: 2024-10-07 17:11:20

js执行上下文的相关文章

一篇文章看懂JS执行上下文

 壹 ? 引 我们都知道,JS代码的执行顺序总是与代码先后顺序有所差异,当先抛开异步问题你会发现就算是同步代码,它的执行也与你的预期不一致,比如: function f1() { console.log('听风是风'); }; f1(); //echo function f1() { console.log('echo'); }; f1(); //echo 按照代码书写顺序,应该先输出 听风是风,再输出 echo才对,很遗憾,两次输出均为 echo:如果我们将上述代码中的函数声明改为函数表达式,

js执行上下文(由浅入深)

每一个函数都有自己的执行上下文EC(执行环境 execution context),并且每个执行上下文中都有它自己的变量对象VO(Variable object),用于存储执行上下文中的变量 .函数声明 .函数参数,这解释了js如何找到我们定义的函数和变量.并且函数是js中唯一一个能创建出作用域的,注意:for,if()else()不能创建作用域.我们通过以下几个例子说明为什么函数和变量的声明会被前置,为什么匿名函数表达式的不可以在外面调用. var a = 18; f1(); function

原型模式故事链(4)--JS执行上下文、变量提升、函数声明

上一章:JS的数据类型 传送门:https://segmentfault.com/a/11... 好!话不多少,我们就开始吧.对变量提升和函数声明的理解,能让你更清楚容易的理解,为什么你的程序报错了~哈哈哈 我们前端的代码一般就三个部分组成html + css +js,一般呢我们的JS又会放在最后执行. 执行上下文:所谓的执行上下文,就是JS代码执行的环境. Javascript中代码的运行环境分为以下三种: 全局上下文 - 这个是默认的代码运行环境,一旦代码被载入,引擎最先进入的就是这个环境.

进阶学习js中的执行上下文

在js中的执行上下文,菜鸟入门基础 这篇文章中我们简单的讲解了js中的上下文,今天我们就更进一步的讲解js中的执行上下文. 1.当遇到变量名和函数名相同的问题. var a = 10; function a(){ console.log(1); } a(); //报错 如果你觉得函数a会覆盖变量a那你肯定是js的新朋友,为什么这里会报错呢?我记得我在基础的执行上下文文章中说过变量声明提前的概念,对这里就是因为这个原因,但是在上面一篇文章中还有一个问题我没有去讲. 那就是函数的声明比变量的声明顺序

Js 作用域与作用域链与执行上下文不得不说的故事 ?(? ???ω??? ?)?

最近在研究Js,发现自己对作用域,作用域链,活动对象这几个概念,理解得不是很清楚,所以拜读了@田小计划大神的博客与其他文章,受益匪浅,写这篇随笔算是自己的读书笔记吧~. 作用域 首先明确一个概念,js只有函数作用域(function-based),没有块级作用域,也就是只有函数会有自己的作用域,其他都没有. 接着,作用域分为全局作用域与局部作用域. 全局作用域中的对象可以在代码的任何地方访问,一般来说,下面情况的对象会在全局作用域中: 最外层函数和在最外层函数外面定义的变量 没有通过关键字"va

js的执行上下文

js中代码有三种类型 : global , function , eval 每一种代码的执行都需要依赖自身的上下文环境 每种代码的执行(程序开始执行,函数被调用,eval代码执行)都会产生一个新的上下文环境,这个上下文环境就称为执行上下(execution context--EC) 执行上下文可以抽象的认为是一个Object,具有一系列属性,其大体结构如下: Execution Context : { variable object : [vars,function declaration,ar

js基础梳理-究竟什么是执行上下文栈(执行栈),执行上下文(可执行代码)?

日常在群里讨论一些概念性的问题,比如变量提升,作用域和闭包相关问题的时候,经常会听一些大佬们给别人解释的时候说执行上下文,调用上下文巴拉巴拉,总有点似懂非懂,不明觉厉的感觉.今天,就对这两个概念梳理一下,加深对js基础核心的理解. 1. 执行上下文(execution context)与可执行代码(execution code) 1.1 首先说一下,可执行代码的类型有哪些: 全局代码:例如加载外部的js文件或者本地标签内的代码.全局代码不包括 function 体内的代码 函数代码:functi

1--面试总结-js深入理解,对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This

参考一手资料:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/中文翻译版本:https://zhuanlan.zhihu.com/p/32042645 Javascript 是一种单线程编程语言,这意味着它只有一个调用栈,call Stack(调用栈 ,,先入后出) 核心:对象,原型链,构造函数,执行上下文堆栈,执行上下文,变量对象,活动对象,作用域链,闭包,This js原型链? 定义 原型对象也是简单的对象并且可以拥有它们自

用实例带你走进this、执行上下文世界[js篇一]

前言: 通过本文你将学习到this的多种用法和使用场景.执行上下文(执行环境)的相关概念. javascript 中this 指向多变.使用场景复杂,也是因其的强大灵活,在前端进阶中也是重要一环,如果能熟练驾驭就能写出更简洁.高质量的代码. 1.执行上下文(执行环境) 在说this之前不得不先说说执行上下文,可以理解为当前代码的执行环境.js中执行环境大概分为三种情况: 全局执行上下文(js运行首次会进入该环境) ---->eg: window对象 函数执行上下文(函数调用) eval JS首次