首页 > 编程语言 >【JavaScript】JS引擎中执行上下文如何顺序执行代码

【JavaScript】JS引擎中执行上下文如何顺序执行代码

时间:2023-02-22 20:45:16浏览次数:38  
标签:上下文 console log 作用域 JavaScript JS 执行 函数

首先我们知道JavaScript引擎包括一个调用栈调用栈是代码实际执行的地方,使用执行上下文(执行环境)来完成;堆是非结构化的内存池,存储了应用程序所需要的所有对象。

执行上下文是什么?

执行上下文包括全局执行上下文和执行上下文。

全局执行上下文:代码编译完成后进入调用栈执行首先创建全局执行上下文(整个项目只有一个全局执行上下文),是用来执行顶层代码(函数除外,函数只在被调用的时候执行)。

执行上下文:执行一段JavaScript的环境,存储了一些代码执行所需要的必要信息,比如传递给函数的局部变量或者参数。打个比方:我们点外卖,送来的袋子(执行上下文)不只有外卖(JavaScript代码),还有餐具(代码执行所需要的必要信息)。

每一个函数调用就会创建执行上下文来执行。

执行上下文分为三个部分,依次为变量环境,作用域和this关键字:

变量环境VE
  • let,const and var变量

  • 函数声明

  • 函数形参

作用域

作用域(scoping):由JavaScript引擎组织和访问,控制我们程序的变量。
主要分为以下三个

  • 全局作用域:在代码中任何地方都能访问到的对象拥有全局作用域。

  • 函数作用域:只能在函数中访问到的对象具有函数作用域,也称局部作用域。

  • 块作用域:ES6新特性,类似于函数作用域,指的是大括号括起来的块,比如if和for循环,块中的变量只能在块中访问,具有块作用域。但只能用let和const,使用var仍能被全局访问。

        if (birthYear >= 1981 && birthYear <= 1996) {
          var millenial = true;
          const str = `oh,you're a millenial,${firstName}`;
          console.log(str);
          function add(a, b) {
            return a + b;
          }
        }
        console.log(str);//str不能被打印
        console.log(add(1, 1));//add函数不能被打印
        console.log(millenial);//var变量能打印,能被全局访问
    

作用域链:若在当前作用域无法查找到需要变量,则通过作用域链来进行变量查找,子作用域查找使用父作用域的变量。

注:如果子作用域和父作用域存在相同的变量名,则直接查找子作用域的,无需进行变量查找。

this关键字

定义:为每个执行上下文(函数)创建的特殊变量,取的值为该函数的调用者本身,具体取值包括以下四种方法 this为调用该方法的对象

  1. 方法 this指向调用方法的对象

    const luki = {
        name : 'lukirence',
        year : 2002,
        calcAge:function(){
    		return 2037-this.year;
        }
    };
    

    如果在方法内的函数嵌套一个新的函数,该嵌套函数相当于常规函数,this关键字为undefined

    const luki = {
      fullName: 'lukirence',
      year: 2002,
      calcAge: function () {
        console.log(this);
        console.log(2037 - this.year);
        const isMillenial = function(){
          console.log(this);//undefined
          console.log(this.year >=1981);
        }
        isMillenial();
      }
    };
    

    如何解决嵌套函数能够使用this?

    1. 添加self变量=this(ES6之前的旧方法)
    const luki = {
      fullName: 'lukirence',
      year: 2002,
      calcAge: function () {
        console.log(this);
        console.log(2037 - this.year);
        const self = this;
        const isMillenial = function(){
          console.log(self);
          console.log(self.year >=1981);
        }
        isMillenial();
      }
    };
    
    1. 将嵌套函数改成箭头函数
    const luki = {
      fullName: 'lukirence',
      year: 2002,
      calcAge: function () {
        console.log(this);
        console.log(2037 - this.year);
        const isMillenial = ()=>{
          console.log(this);
          console.log(this.year >=1981);
        }
        isMillenial();
      }
    };
    
  2. 常规函数声明 this为undefined

    const calcAge = function (birthYear) {
      console.log(2037 - birthYear);
      console.log(this);//显示undefined
    };
    calcAge(1991);
    
  3. 箭头函数 箭头函数没有this关键字,箭头函数的关键词会通过查找父函数的关键词,若没有则为全局的关键词,即指向全局窗口。

    console.log(this);//指向全局窗口window
    
    const calcAgeArrow = birthYear => {
      console.log(2037 - birthYear);
      console.log(this);//指向全局窗口window
    };
    calcAgeArrow(1991);
    
    const luki = {
      fullName: 'lukirence',
      year: 2002,
      calcAge: function () {
        console.log(this);
        console.log(2037 - this.year);
      },
      greet: () => {
        console.log(`hi,${this.fullName}`);
      },
    };
    luki.greet();//显示hi undefined,因为this指向window对象
    

  1. 事件监听 this为事件处理器所添加的DOM元素

注:箭头函数的执行上下文不包括参数对象和this关键字

执行上下文创建

在详细了解了执行上下文的内容后,我们来看一段代码实际执行时执行上下文如何在调用栈中活动的。

将以以下代码为例,按每一步骤描述执行上下文创建流程:

const name = 'luki';//--------------------------------1
const first =() =>{//---------------------------------2
    let a =1;//-------------------------------------2.1
    const b =second(1,2);//-------------------------2.2
    a=a+b;//----------------------------------------2.3
    return a;//-------------------------------------2.4
};
function second(x,y){//-------------------------------3
    var c =2;//-------------------------------------3.1
    return c;//-------------------------------------3.2
}
const x =first();//-----------------------------------4
  1. 代码被编译后先创建全局执行上下文推入调用栈(call stack);

  2. 执行顶层代码(序号1,2,3):运行1声明name变量; 运行2声明first函数;运行3声明second函数;保存以上变量环境到全局上下文中;

  3. 执行到序号4开始调用first()函数,并创建first()的执行上下文推入调用栈,准备执行first()内部代码跳转到2.1;

  4. 运行到2.1声明变量a保存到first()的执行上下文;

  5. 运行2.2调用新函数second(),创建second()的执行上下文推入调用栈,停止first()的执行跳转到3.1;

  1. 运行3.1声明变量c保存到second()的执行上下文;

  2. 运行3.2return语句表示完成该函数执行,second()的执行上下文将从调用栈中弹出(此处虽然弹出,但是其中变量环境仍可能被使用,涉及到闭包的概念),调用栈重新指向first(),代码重新跳转回2.3;

  1. 运行2.3执行代码内容;

  2. 运行2.4,first()的执行上下文将从调用栈中弹出,调用栈重新指向gloal(),代码重新跳转回4,将返回值最终赋值给x;

  1. 此后调用栈一直保持在这个状态直到我们关闭浏览器来终止程序,最终弹出global()全局上下文;

由此我们可以发现调用栈的执行上下文根据函数调用来出入栈确保了JS引擎能正确执行代码的顺序。

标签:上下文,console,log,作用域,JavaScript,JS,执行,函数
From: https://www.cnblogs.com/lukirence/p/17145736.html

相关文章

  • 用 Tensorflow.js 做了一个动漫分类的功能(一)
    前言:    浏览某乎网站时发现了一个分享各种图片的博主,于是我顺手就保存了一些。但是一张一张的保存实在太麻烦了,于是我就想要某虫的手段来处理。这样保存的确是很......
  • 用 Tensorflow.js 做了一个动漫分类的功能(二)
    前言:    前面已经通过采集拿到了图片,并且也手动对图片做了标注。接下来就要通过Tensorflow.js基于mobileNet训练模型,最后就可以实现在采集中对图片进行自动分......
  • 小程序 app.js中登录获取token还未结束时 首页请求过快报未登录
    场景:在小程序中大家应该都有这样的场景,在onLaunch里用wx.login静默登录拿到code,再用code去发送请求获取token、用户信息等,整个过程都是异步的,然后我们在业务页面里onLoad......
  • tensorflow.js 对视频 / 直播人脸检测和特征点收集
    前言:    这里要介绍的是Tensorflow.js官方提供的两个人脸检测模型,分别是face-detection和face-landmarks-detection。他们不但可以对视频中的人间进行精确定......
  • tensorflow.js 多分类,机器学习区分企鹅种类
    前言:    在规则编码中,我们常常会遇到需要通过多种区间判断某种物品分类。比如二手物品的定价,尽管不是新品没有SKU但是基本的参数是少不了。想通过成色来区分某......
  • tensorflow.js 视频图片多目标检测
    前言:    Tensorflow.js官方提供了很多常用模型库,涵盖了平时开发中大部分场景的模型。例如,前面提到的图片识别,除此之外还有人体姿态识别,目标物体识别,语音文字等识......
  • C# json数组排序-根据指定key排序-jsonArray
    //jsonArray.ToJson()是json数组根据指定treatment_no来进行排序json字符串[{"treatment_type":"1","treatment_no":"42",},{"treatment_type":......
  • js: ElementUI表单验证validate和validateField
    文档回顾1、validate:对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则......
  • js中的函数的各种形态 230222
    标准函数functionfn(){console.log(1111)}fn()匿名函数等号右边是匿名函数varfn=function(){console.log(222)}fn()自启动函数本质还是匿名函数(function()......
  • Javascript进阶
    Javascript进阶一.变量提升看以下代码,或多或少会有些问题的.functionfn(){console.log(name);varname='大马猴';}fn()发现问题了么.这么写代码,......