当前位置: 首页 > news >正文

前端 js 之 代码执行的一个过程 02

嘿,欢迎你来 !💕

文章目录

  • 前言
  • 一、运行一个 js 文件
  • 二、运行环境
  • 三、js执行代码的过程(普通变量)
  • 四、打印 window
  • 五、js执行代码的过程(函数变量)
  • 六、函数调用函数的过程
  • 注意!!!
  • 最后、作用域与作用域链面试题


前言


在上一篇文章里,我们简单说了浏览器的工作原理和v8引擎的原理



浏览器渲染

  1. 首先先下载 index.html ,遇到css 或者script 文件就下载,
  2. 通过浏览器内核进行解析 index.html
  3. 如果解析过程中遇到 js 代码就立即执行 js 代码,因为js代码属于高级语言,cpu不能直接执行,所以借助js引擎
  4. 对于v8 引擎来说,通过parse模块把我们的代码解析成 AST 树型结构,再通过ignation转化为字节码,再编译成低级语言,cpu就可以执行这些指令了

那今天我们研究的就是 js源代码到AST抽象语法树他进行解析,是如何解析的。


上篇文章整理了很久,多多少少有了点概念,今天这篇文章是基于上篇基础上的加深,希望我表达的足够清晰,如果错处,还望指正,感谢,biubiu ~💕


一、运行一个 js 文件


我们以下的讲解都是基于早期的ECMA的版本规范,也就es5之前的。也发现了所有的变量定义都是用的 var。

在早期的版本规定里是这样定义的:每个执行上下文都会被关联到一个变量环境(VO: variable Object,它是一个对象),源代码中的变量和函数都会 被作为属性 添加到VO中,对于函数来说,参数也会被添加到VO中

在最新的的ECMA 版本规范中,每个执行上下文会关联到一个变量环境中,在执行代码中变量和函数的声明会 作为环境纪录 添加到变量环境中,对于函数来说,参数也会被作为环境记录添加到环境变量中

const name = "haha";const name2 = "haha2";console.log(name);

假设这是一个 js 文件, 想在浏览器上运行,首先得有一个index.html ,通过script 引入才能运行。js引擎怎么运行的呢?


二、运行环境


我们编写的JS代码都是需要在一个环境中运行的:比如

  1. 浏览器(引擎):例如webkit,gecko,Trident, blink
  2. node*(基于V8渲染js)
  3. webview(v8引擎)
  4. JS之所以能够在浏览器中运行,是因为浏览器给JS提供了执行的环境 => 栈内存

先说几个概念:(不太理解也没关系)

  1. 栈内存 ( ECStack(Execution Context Stack):执行环境栈) :它是代码执行环境;它是浏览器分配的内存空间,用来执行代码 。
  2. 全局对象GO(Globle Object)): 该对象所有作用域都可以访问, 它用来存放当前环境的内置方法,类,变量等,他还有个window属性指向自己;这就是为什么我们可以直接使用Math,String,setTimeout 等方法 ,这里请注意!!对于方法,类这种复杂类型数据存放的是对应的内存地址,堆内存才是真正的存放代码
  3. 堆内存(Heap) :存放东西(属性和方法(例:isNaN:function…))
  4. 任何开辟的内存都有一个16进制的内存地址,方便后期找到这个内存,ox开头
  5. 执行上下文ECS(Execution Context stack) :在编程语言中,代码执行中,为了区分全局变量和函数执行所处的不同的作用域(目的是为了区分每个词法作用域下代码的独立性),会产生执行上下文栈,一个是全局执行上下栈 GEC,一个是函数执行上下文栈FEC,都会在ECS里运行
  6. 全局执行上下栈 GEC: 包括两部分,第一部分,在代码执行前,在paese转化为AST的过程中,会将全局定义的变量,函数等加入到 GO里,但是不会赋值(也称为变量的提升);第二部分,是代码的执行,变量赋值,或者执行函数等等
  7. 函数执行上下文栈FEC:包括三部分,第一部分,在解析函数成为AST树结构时,会创建一个AO,AO中包括形参、arguments、函数定义和指向函数对象、定义的变量;第二部分,作用域,由当前AO对象和父级VO组成,查找是会一层层查找;第三部分,this的绑定值(本篇先不说)

三、js执行代码的过程(普通变量)

const name = "haha";const name2 = "haha2";console.log(name);var golbalObject={String:'类',Date:'类',setTimeout:'方法',window:golbalObject,name:undefined,name2:undifined}
  1. 再代码被解析之前,运行之前,v8 引擎内部会帮助我们创建一个对象,全局变量(GlobalObject,又称为GO),
  2. 这个GlobalObject 存放着当前环境的全局对象,该对象所有的作用域都可以访问,
  3. 里面包括 Math,Date,settimeout…等 方法 ,还有一个 window属性 指向自己
  4. 在代码编译的时候,它可以确定我们定义了哪些变量,然后将这些变量添加到全局对象里面
  5. 因为我们还没有真正的执行,所以这些变量都是undefined(变量存放在GO) ,
  6. v8 为了执行代码,v8引擎内部会有一个全局执行上下文栈(全局代码需要被执行的时候才会创建,称为EGC),有且只有一个,EGC 包括两部分: 第一部分,称为VO,在代码执行前,在paese转化为AST的过程中,会将全局定义的变量,函数等加入到 GO里,但是不会赋值(也称为变量的提升),所以这个VO对应的是GO;第二部分,是代码的执行,变量赋值,或者执行函数等等
  7. 比如现在要执行 var name=30 这个代码;它就会去VO里面找,VO对应GO;再把GEC放到调用栈里执行

请添加图片描述


四、打印 window

const name = "haha";const name2 = "haha2";console.log(name);var golbalObject={String:'类',Date:'类',setTimeout:'方法',window:golbalObject,name:undefined,name2:undifined,}console.log(window)

当打印window时,发现这个对象包括很多东西,很多内置方法,包括name,name2等属性,是因为这个window指向时golbalObject,正如上面所说他一个window属性 指向自己

五、js执行代码的过程(函数变量)

1.   foo();2.   function foo() {3.      console.log("开心快乐向前冲");4.  }

提前声明 ps:

  1. 我们所有代码在执行前都要加载到内存里,(代码存放在磁盘,再进入内存,转化为机器语言,最后才能被cpu执行)
  2. 在内存里,会划分为栈结构和堆结构,简单类型数据放在栈里,复杂类型数据地址放在栈,值放在堆

运行的不仅仅是普通变量,那对于函数来说,他是一个怎么样的过程呢?

  1. 根据上面所说,在编译阶段,会把变量添加到全局对象里,在未运行之前值为undefined,
  2. 但是foo 在定义之前执行,但是能执行所有的代码,为什么可以打印出来foo呢?
  3. 因为是在编译,所以第一行代码没有执行;第二行发现声明了一个函数,他也会定义 foo在GO里,但是不同的是,因为函数较特殊,他会再开辟一个新的内存空间,用来存放函数, 函数执行上下文栈FEC(先理解这一块,下面会具体说) ,foo这里存放的就是函数对应的内存空间地址
  4. 理解成指针、引用,因为一个地址可以对应多个变量,也是为什么复杂类型数据会互相影响
  5. 以上是编译的过程,当执行到第二行时 foo() ,【请留意,他其实是两部分,foo 和()】,他会再VO (对应的是GO) 里面查找Foo,他发现是个内存地址,就会根据地址找到这个空间;()表示函数的执行,就会把我们 FEC 放入到 调用栈 里面执行。


请添加图片描述



为了不饶晕乎,我们先把以上理解清除,再往下看

1.   foo();2.   var name=1233.   function foo(num) {4.    	num=15.     console.log("开心快乐向前冲");6. 	console.log(name)7.  }
  1. 我们把对应的函数空间放到调用栈不是直接运行,而是创建一个函数执行上下文 :包括三部分,第一部分,在解析函数成为AST树结构时,会创建一个AO,AO中包括形参、arguments、函数定义和指向函数对象、定义的变量;第二部分,作用域,由当前AO对象和父级VO组成,查找是会一层层查找;第三部分,this的绑定值(本篇先不说);
  2. 在第六行的时候,我们发现在Ao 里面并没有name这个值,为什么使用了全局的name呢?
  3. 是这样的,当我们查找一个变量时,真实的查找路径是沿着作用域链来查找的
  4. 函数执行上下文不仅仅包括 **VO** ,还有一个 **scope chain** ,叫做作用域链 (看图二)
  5. 一个函数执行上下文的作用域链有两部份组成,当前 AO 的作用域 + 父级作用域
  6. (父级作用域在函数编译时就确定了)
  7. 他的执行顺序是:先在自己的函数执行上下文找,再向他的上级作用域找 所以你理解为什么可以使用name了吗 ?
  8. 一旦函数执行完毕,这个函数执行上下文就会弹出调用栈,就会销毁了,这个 ao 也因为没有指向也会被销毁掉
  9. 当再执行时,是重新创建了一个函数执行上下文,把以上的过程再走一遍



请添加图片描述




六、函数调用函数的过程

我们在上面看了普通变量的执行过程和函数的执行过程,其实发现很简单,调用栈帮我们执行代码,为了区分变量还是函数,我们使用全局执行上下文栈函数执行上下文栈帮助我们执行,编译过程中定义了,真正运行时才是会有赋值等操作。只有函数才有作用域,当我们在一个函数里使用了当前作用域没有定义的变量,而全局变量存在的变量时,也可以使用,是因为沿着作用域链来查找的。在函数定义的时候,他的内存地址里存放两个东西,一个是他的父级作用域和他的执行块

那我们现在看看函数调用函数的过程
其实也很简单,在函数里调用函数时,他发现有函数定义执行时,会再次创建一个函数执行上下文栈,用来存放新的函数,这个函数的VO 同样存储两个东西,一个是作用域(父级作用域和当前作用域)和代码块,如上,所以在函数里调用函数 ,也是按照作用域链查找变量,所以与定义的位置无关

注意!!!


        我们以上的讲解都是基于早期的ECMA的版本规范,也就es5之前的。也发现了所有的变量定义都是用的 var。

在早期的版本规定里是这样定义的: 每个执行上下文都会被关联到一个变量环境(VO: variable Object),再源代码中的变量和函数都会被作为属性添加到VO中,对于函数来说,参数也会被添加到VO中

在最新的ECMA版本规范中,进行了新的改动:每一个执行上下文会关联到一个变量环境中(variableEnvironment),在执行代码中变量和函数的声明会作为环境记录添加到变量环境中,对于函数来说,参数也会被作为环境记录添加到变量环境中

        通过上面的变化,我们可以得知,在最新的ECMA标准中,我们前面的变量对象VO已经有另外一个称呼环境变量,VE



在这里插入图片描述

最后、作用域与作用域链面试题

函数表达式遵循变量提升规则,
今天我的表达还可以吗?🤣

相关文章:

前端 js 之 代码执行的一个过程 02

嘿,欢迎你来 !💕 文章目录 前言一、运行一个 js 文件二、运行环境三、js执行代码的过程(普通变量)四、打印 window五、js执行代码的过程(函数变量)六、函数调用函数的过程注意!&…...

【经验分享】如何构建openGauss开发编译提交一体化环境

前文 本文适合对openGauss源代码有好奇心的爱好者,那么一个友好的openGauss源代码环境应该是怎么样的。openGauss的开发环境是如何设置的?openGauss的编译环境是如何构建的?如何向openGauss提交代码,笔者集合官方和几位博主实践提…...

儿童疫苗接种:安全与注意事项

引言: 儿童的疫苗接种是维护其健康和预防传染病的重要措施。疫苗可以有效地保护儿童免受各种疾病的威胁,但在接种过程中需要家长和监护人特别关注一些注意事项,以确保接种的安全性和有效性。本文将深入探讨儿童疫苗接种的重要性,…...

Go 代码块与作用域,变量遮蔽问题详解

Go 代码块与作用域详解 文章目录 Go 代码块与作用域详解一、引入二、代码块 (Block)2.1 代码块介绍2.2 显式代码块2.3 隐式代码块2.4 空代码块2.5 支持嵌套代码块 三、作用域 (Scope)3.1 作用域介绍3.2 作用域划定原则3.3 标识符的作用域范围3.3.1 预定义标识符作用域3.3.2 包代…...

可观测性-Metrics-WebClient异步Http远程Call

代码示例 1.依赖导入 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><ar…...

Android之播放本地视频和Url视频方法

一、播放本地视频文件 根据文件路径在浏览器中播放&#xff0c;可用于视频预览等场景 效果&#xff1a; 用浏览器播放本地视频 文件路径例子&#xff1a; /storage/emulated/0/Android/data/com.custom.jfrb/files/Movies/1697687179497.mp4 File file new File("文件…...

设计模式:工厂方法模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):

本节主要介绍设计模式中的工厂方法模式。 简介&#xff1a; 工厂方法模式&#xff0c;它是对简单工厂模式的进一步抽象化&#xff0c;其好处是可以使系统在不修改原来代码的情况下引进新的产品&#xff0c;即满足开闭原则。 它定义了一个用于创建对象的工厂接口&#xff0c;让…...

C++基础——指针

1 概述 指针的作用&#xff1a;可以通过指针间接访问内存 内存编号从0开始&#xff0c;一般使用十六进制数字表示&#xff0c;指针可以保存地址 2 指针变量定义和作用 int main() {//1、指针的定义int a 10; //定义整型变量a//指针定义语法&#xff1a; 数据类型 * 变量名 …...

PLC 学习day02 硬件输入/输入的知识

1.资料来源 1.链接&#xff1a;三菱PLC视频教程全集之FX3U基本单元输入接线_哔哩哔哩_bilibili 2. 链接&#xff1a; 三菱plc视频教程全集之FX3U基本单元输出接线_哔哩哔哩_bilibili 2. PLC 的输入部分器件连接。 2.1 PLC输入部分的硬件知识 1. 一般输入部分是PLC获取信息的地…...

rabbitMq (2)

RabbitMQ 消息应答与发布 文章目录 1. 消息应答1.2 自动应答1.2 手动应答1.3 代码案例 2. RabbitMQ 持久化2.1 队列持久化2.2 消息持久化 3. 不公平分发4. 预取值分发5. 发布确认5.1 发布确认逻辑5.2 开启发布确认的方法5.3 单个确认发布5.4 批量确认发布5.5 异步确认5.5.1 处理…...

通讯协议学习之路:RS422协议理论

通讯协议之路主要分为两部分&#xff0c;第一部分从理论上面讲解各类协议的通讯原理以及通讯格式&#xff0c;第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN&#xff1b;视频会发布在bilibili(UID:399951374) 一、…...

剪映failed to initialize,cuda.is_available()为false解决

debug记录帖 错误1&#xff1a;打开剪映发现弹窗提示failed to initialize graphics backed for D3D11 错误2&#xff1a;torch版本、cuda版本&#xff08;之前的正常环境&#xff09;都对但是torch.cuda.is_available()为false 怀疑是显卡驱动的问题 打开Nvidia Geforce Exp…...

基于Spring Boot的LDAP开发全教程

写在前面 协议概述 LDAP&#xff08;轻量级目录访问协议&#xff0c;Lightweight Directory Access Protocol)是一种用于访问和维护分布式目录服务的开放标准协议,是一种基于TCP/IP协议的客户端-服务器协议&#xff0c;用于访问和管理分布式目录服务&#xff0c;如企业内部的…...

在 Linux 上保护 SSH 服务器连接的 8 种方法

SSH 是一种广泛使用的协议&#xff0c;用于安全地访问 Linux 服务器。大多数用户使用默认设置的 SSH 连接来连接到远程服务器。但是&#xff0c;不安全的默认配置也会带来各种安全风险。 具有开放 SSH 访问权限的服务器的 root 帐户可能存在风险。尤其是如果使用的是公共 IP 地…...

摩尔信使MThings的协议转换(数据网关)功能

摩尔信使MThings可以作为现场总线&#xff08;RS485&#xff09;和以太网的数据中枢&#xff0c;并拥有强大的Modbus协议转换功能。 数据网关功能提供协议转换和数据汇聚功能&#xff0c;可实现多维度映射&#xff0c;包括&#xff1a;不同的通道(总线)类型、协议类型&#xff…...

Mac安装Kali保姆级教程

Mac安装Kali保姆级教程 其他安装教程&#xff1a;使用VMware安装系统Window、Linux&#xff08;kali&#xff09;、Mac操作系统 1 虚拟机安装VM Fusion 去官网下载VM Fusion 地址&#xff1a;https://customerconnect.vmware.com/en/evalcenter?pfusion-player-personal-13 …...

利用Spring Boot框架做事件发布和监听

一、编写事件 1.编写事件类并集成spring boot 事件接口&#xff0c;提供访问事件参数属性 public class PeriodicityRuleChangeEvent extends ApplicationEvent {private final JwpDeployWorkOrderRuleDTO jwpDeployWorkOrderRuleDTO;public PeriodicityRuleChangeEvent(Obje…...

KingBase库模式表空间和客户端认证(kylin)

库、模式、表空间 数据库 数据库基集簇与数据库实例 KES集簇是由单个KES实例管理的数据库的集合KES集簇中的库使用相同的全局配置文件和监听端口、共享相关的进程和内存结构同一数据库集簇中的进程、相关的内存结构统称为实例 数据库 数据库是一个长期存储在计算机内的、有…...

h5的扫一扫功能 (非微信浏览器环境下)

必须在 https 域名下才生效 <template><div><van-field label"服务商编码" right-icon"scan" placeholder"扫描二维码获取" click-right-icon"getCameras" /> <div class"scan" :style"{disp…...

Typora 导出PDF 报错 failed to export as pdf. undefined 解决方案

情况 我想把一个很大的markdown 导出为 248页的pdf 然后就报错 failed to export as pdf. undefined 原因 &#xff1a; 个人感觉应该是图片太大了 格式问题之类导致的 解决 文件 -> 偏好设置 - > 导出 -> pdf -> 自定义 -> 把大小全部改为24mm (虽然图中是32 …...

[架构之路-239]:目标系统 - 纵向分层 - 中间件middleware

目录 前言&#xff1a; 一、中间件概述 1.1 中间件在软件层次中的位置 1.2 什么是中间件 1.3 为什么需要中间件 1.4 中间件应用场合&#xff08;应用程序不用的底层需求&#xff1a;计算、存储、通信&#xff09; 1.5 中间件分类 - 按内容分 二、嵌入式系统的中间件 2…...

javascript利用xhr对象实现http流的comet轮循,主要是利用readyState等于3的特点

//此文件 为前端获取http流 <!DOCTYPE html> <html xmlns"http://www.w3.org/1999/xhtml" lang"UTF-8"></html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"/&g…...

【Mybatis源码】XPathParser解析器

XPathParser是Mybatis中定义的进行解析XML文件的类,此类用于读取XML文件中的节点文本与属性;本篇我们主要介绍XPathParser解析XML的原理。 一、XPathParser构造方法 这里我们介绍主要的构造方法 public XPathParser(InputStream inputStream, boolean validation, Propert…...

辉视智慧酒店解决方案助力传统酒店通过智能升级焕发新生

辉视智慧酒店解决方案基于强大的物联网平台&#xff0c;将酒店客控、网络覆盖、客房智能化控制、酒店服务交互等完美融合&#xff0c;打造出全方位的酒店智慧化产品。利用最新的信息化技术&#xff0c;我们推动酒店智慧化转型&#xff0c;综合运用前沿的信息科学和技术、消费方…...

文件和命令的查找与处理

1.命令查找 which which 接命令 2.文件查找 find 按文件名字查找 准确查找 find / -name "hosts" 粗略查找 find / -name "ho*ts" 扩展名查找 find / -name "*.txt" 按文件类型查找 find / -type f 文件查找 find / -ty…...

第七章:最新版零基础学习 PYTHON 教程—Python 列表(第三节 -Python程序访问列表中的索引和值)

有多种方法可以访问列表的元素,但有时我们可能需要访问元素及其所在的索引。让我们看看访问列表中的索引和值的所有不同方法。 目录 使用Naive 方法访问列表中的索引和值 使用列表理解访问列表中的索引和值...

接口测试面试题整理​​​​​​​

HTTP, HTTPS协议 什么是DNSHTTP协议怎么抓取HTTPS协议说出请求接口中常见的返回状态码http协议请求方式HTTP和HTTPS协议区别HTTP和HTTPS实现机有什么不同POST和GET的区别HTTP请求报文与响应报文格式什么是Http协议无状态协议?怎么解决HTTP协议无状态协议常见的POST提交数据方…...

【保姆级教程】ChatGPT/GPT4科研技术应用与AI绘图

查看原文>>>https://mp.weixin.qq.com/s?__bizMzAxNzcxMzc5MQ&mid2247663763&idx1&snbaeb113ffe0e9ebf2b81602b7ccfa0c6&chksm9bed5f83ac9ad6955d78e4a696949ca02e1e531186464847ea9c25a95ba322f817c1fc7d4e86&token1656039588&langzh_CN#rd…...

凉鞋的 Godot 笔记 202. 变量概述与简介

202. 变量概述与简介 想要用好变量不是一件简单的事情&#xff0c;因为变量需要命名。 我们可以从两个角度去看待一个变量&#xff0c;第一个角度是变量的功能&#xff0c;第二个是变量的可读性。 变量的功能其实非常简单&#xff0c;变量可以存储一个值&#xff0c;这个值是…...

HTML 常用标签及练习

常用标签 <head>中的标签 概述 head中的内容不显示到页面上 标签说明<title>定义网页的标题<meta>定义网页的基本信息&#xff08;供搜索引擎&#xff09;<style>定义CSS样式<link>链接外部CSS文件或脚本文件<script>定义脚本语言<…...