当前位置: 首页 > 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 …...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...

pycharm 设置环境出错

pycharm 设置环境出错 pycharm 新建项目&#xff0c;设置虚拟环境&#xff0c;出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...