JavaScript 之 作用域变量提升闭包

一、JavaScript 代码的执行

  • 浏览器内核是由两部分组成的,以 webkit 为例
    • WebCore:负责HTML解析、布局、渲染等等相关的工作
    • JavaScriptCore:解析、执行 JavaScript 代码
  • 另外一个强大的 JavaScript 引擎就是 V8 引擎

二、深入 V8 引擎原理

  • V8 是用 C ++ 编写的 Google 开源高性能 JavaScript 和 WebAssembly (未来 js 替代)引擎,它用于 Chrome 和 Node.js
    • 跨平台
  • 它实现 ECMAScriptWebAssembly ,并在 Windows 7 或更高版本,macOS 10.12+ 和使用 x64,IA-32,ARM 或 MIPS 处理器的 Linux 系统上运行
  • V8 可以独立运行,也可以嵌入到任何 C ++ 应用程序
  • 步骤
    • 高级语言转化成二进制代码
      • 抽象语法树
        • 知道整个代码的结构
      • 字节码
        • 类似于汇编代码
        • 跨平台
          • mac os
          • java:一次编写,到处运行
            • 需要安装并依赖于 java 虚拟机
      • 优化的机器码
        • 尽量保证传入的参数的类型一致
        • ts 能够提高代码性能
    • lgnition:AST 转化为字节码
    • TurboFan

三、V8 引擎的架构

  • 浏览器中存在渲染引擎,v8 是专门用于处理 js 代码的一部分

  • Scanner 进行扫描,进行词法分析

  • V8 引擎本身的源码非常复杂,大概有超过100w行C++代码

  • Parser 模块将 JavaScript 代码转换成 AST(抽象语法树)

    • 进行语法分析

    • 预解析(声明时候没有进行调用,被认为是不被执行的代码,进行预解析,后面执行的话就会进行全量解析) =》 全量解析(函数立即执行,只进行一次全量解析)

      • 避免函数嵌套
    • 解释器并不直接认识 JavaScript 代码

    • 如果函数没有被调用,那么是不会被转换成 AST 的

  • Ignition 是一个解释器,会将 AST 转换成 ByteCode(字节码)

    • 会收集 TurboFan 优化所需要的信息(比如函数参数的类型信息,有了类型才能进行真实的运算)
    • 如果函数只调用一次,Ignition会解释执行ByteCode
  • TurboFan是一个编译器,可以将 字节码 编译为 CPU 可以 直接执行的机器码

    • 如果一个函数被多次调用,会被标记为热点函数,那么就会经过 TurboFan 转换成优化的机器码,提高代码的执行性能
    • 但是,机器码实际上也会被还原为 ByteCode
      • 如果后续执行函数的过程中,类型发生了变化(比如sum函数原来执行的是number类型,后来执行变成了string类型)
      • 之前优化的机器码并不能正确的处理运算,就会逆向的转换成字节码
  • 词法分析(对一条语句进行此法分析,提取出关键字)=》 语法分析(解析成 js 中对应的语法,生成对应的 AST 树

image.png

四、初始化全局对象

  • js 引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO)
    • 该对象 所有的作用域(scope)都可以访问
    • 里面会包含 Date、Array、String、Number、setTimeout、setInterval 等等
    • 其中还有一个 window 属性指向自己

五、执行上下文

  • js 引擎内部有一个执行上下文栈(Execution Context Stack,简称 ECS),它是用于执行代码的调用栈
    • 执行的是全局的代码块
      • 全局的代码块为了执行会构建一个 全局执行上下文 Global Execution Context(GEC)
      • GEC 会被放入到 执行上下文栈 ECS 中执行
  • GEC 被放入到 ECS 中里面包含两部分内容
    • 第一部分:变量的作用域提升:在代码执行前,在 parser 转成 AST 的过程中,会将全局定义的变量、函数等加入到 GlobalObject 中,但是并不会赋值
    • **第二部分:**在代码执行中,对变量赋值,或者执行其他的函数

六、VO 对象

  • 每一个执行上下文会关联一个 VO(Variable Object,变量对象),变量和函数声明会被添加到这个 VO 对象中
  • 全局代码被执行的时候,VO 就是 GO 对象
  • 全局对象就是 window 对象,this
  • 作用域链

七、函数执行

  • 在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(Functional Execution Context,简称 FEC),并且压入到 EC Stack
  • 每个执行上下文都会关联一个 VO,函数执行上下文关联的 VO 是什么
    • 当进入一个函数执行上下文时,会在堆内存中创建一个 AO 对象(Activation Object)
    • 这个 AO 对象会使用 arguments 作为初始化,并且初始值是传入的参数
    • 这个 AO 对象会作为执行上下文的 VO 来存放变量的初始化(都是 undefined)
  • 执行完后就销毁
  • 只有是函数的时候才会指向一个地址,其他都是 undefined
    • 创建 obj 对象(刚开始也是 undefined )
  • 函数多层嵌套,并不会把所有的对象都创建出来,只会创建第一个

八、JavaScript 的代码的执行流程

  • 首先在执行前会现在堆内存中开辟一块空间 (GO) 存放一些初始的值 如 Number String等等
  • 还有代码中定义的一些变量 函数(在 parser 转成 AST 树的过程中存放在 GO 中的 )并没有赋值
  • 同时在执行代码时在执行上下文栈(ECS)中存放一个全局执行上下文(GEC) 用于执行代码
    • GO中对应的函数 也会在堆内存中开辟出空间 为 Function Object 初始一些数据(name length scope chain等)
  • 开始执行代码
  • 每个EC中有着三个重要的内容(VO scope chain 以及this)
  • VO指向对应的作用域(全局作用域(GO) 函数作用域(AO))
1. 基本数据类型是按值进行操作
2. 基本数据类型是存放在栈区的
3. 无论当前看到的栈内存还是引用数据类型会使用的堆内存都属于计算机内存
4. GO 

九、作用域和作用域链

  • 当进入到一个执行上下文时,执行上下文也会关联一个作用域链Scope Chain
    • 作用域链是一个对象列表,用于变量标识符的求值
    • 当进入一个执行上下文时,这个作用域链被创建,并且根据代码类型,添加一系列的对象
  • 代码类型
    • 全局代码
    • 函数代码
  • 函数被创建的时候,作用域链已经确定了
    • 因此可以画出

十、GO/AO/VO以及作用域和作用域链

  • GO

    • Global Object JS代码在执行前会现在堆内存中创建一个全局对象(GO)
    • 有自己的地址,可以对其进行访问
    • 用于存放一些定义好的变量方法等
    • 包含 Date Array String Number setTimeout等
    • 同时有一个 window 属性指向自己
    • 同时在语法分析转成 AST 的过程中也会将一些变量 函数 存放在 GO 中 只是变量的初始值为 undefined
  • AO

    • 函数在执行前会先在堆内存中创建一个AO(Activation Object)对象 里面存放这arguments 对应函数的形参 以及在函数中定义的变量 初始值为 undefined
  • VO

    • Variable Object 在执行函数时 会在执行上下文栈(ECS)中进入一个函数执行上下文(FEC)其中有三个核心
    • 核心之一是VO 指向的是该函数在内存中解析时创建的AO 而在全局执行上下文中指向的是GO
  • 作用域,作用域链

    • 当进入到一个执行上下文时 执行上下文会关联一个作用域链
    • 通常作用域链在解析时就被确定,因此,作用域链域函数的定义位置有关,而与它的调用位置无关

十一、面试题

    // 1.面试题一:// var n = 100// function foo() {//   n = 200 //直接访问上一层的 n // }// foo()// console.log(n)//200// 2.面试题二:// var n = 100// function foo() {//   console.log(n)//   var n = 200//   console.log(n)// }// foo()//undefined  200// 3.面试题三:// var n = 100// function foo1() {//   console.log(n)// }// function foo2() {//   var n = 200//   console.log(n)//   foo1()// }// foo2() //200 100// 4.面试题四:// var n = 100// function foo() {//   console.log(n)//   return//执行// 解析的时候//   var n = 200  //还是会在里面定义n:undefined// }// foo()// 5.在开发中可能会出现这样错误的写法// function foo() {//   message = "Hello World"//就是当成 全局变量 进行解析,没有 var// }// foo()// console.log(message)// 6.面试题五:function foo() {var a = b = 100}foo()console.log(a)//访问不到,报错console.log(b)//当成全局变量 100

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面向对象三大特征之多态

在之前的文章,我们分别介绍了类与对象、面向对象三大特征的封装、以及继承(一)、继承(二)。这一篇文章,我们介绍Java面向对象三大特征的最后一个——多态。 多态 多态的概述 概念:完成某个行为…

CVE-2024-23897 Jenkins 任意文件读取漏洞

项目介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。Jenkins是开源CI&CD软件领导者, 提供超过1000个插…

Java集合相关面试题

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。 📗本文收录于java面试题系列,大家有兴趣的可以看一看 📘相关专栏Rust初阶教程、go语言基…

C# 设置一个定时器函数

C#中,创建设置一个定时器,能够定时中断执行特定操作,可以用于发送心跳、正计时和倒计时等。 本文对C#的定时器简单封装一下,哎,以方便定时器的创建。 定义 using Timer System.Timers.Timer;class SetTimer {Timer …

OSPF协议基础(OSPF工作过程)

目录 OSPF基本工作原理邻居建立过程Router ID发现并建立邻居 - Hello报文OSPF邻居建立过程 链路状态信息丰富的数据链路层支持能力网络类型 - P2P网络网络类型 - 广播型网络网络类型 - NBMA网络网络类型 - P2MP网络OSPF的度量方式 报文类型及作用OSPF协议报文头部OSPF报文类型O…

k8s-调度

调度 从上面的架构图我们可以看到,调度是工作在Master,负责调度Pod,为POD分配Node。 调度的工作原理 #查看所有的Node kubectl get nodes 我们可以看到节点有一个Name,这就是调度的关键。 调度的步骤: 1 创建POD的时候每一个POD都会有一个叫NodeName的…

老板为何都对项目经理毕恭毕敬!因为这个职位一念成佛一念成魔

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩! 老板为何都对项目经理毕恭毕敬!因为这个职位一念成佛一念成魔 曾几何时&am…

Linux:命名管道及其实现原理

文章目录 命名管道指令级命名管道代码级命名管道 本篇要引入的内容是命名管道 命名管道 前面的总结中已经搞定了匿名管道,但是匿名管道有一个很严重的问题,它只允许具有血缘关系的进程进行通信,那如果是两个不相关的进程进行通信&#xff0…

《佛法修学概要》009-012集研讨

课程摘要 9、只有走出心中的妄想,才可能接觸彌陀的光明! 佛陀在經典裡講出一個譬喻,說有一座動物園,這座動物園關了很多動物。其中有一隻袋鼠,就是澳洲那種很會跳的袋鼠。動物園的管理員,給牠圈了一個十公尺…

《合成孔径雷达成像算法与实现》Figure5.16

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

【vue oidc-client】invalid_requestRequest Id: 0HN0OOPFRLSF2:00000002

需求:完成统一登录,需要从三方平台跳到我们的平台。 oidc-client报错记录。这个一般是配置信息出错,需要和三方平台进行沟通,一定要把client_id,密钥进行对应; 同时关于此次出错还修改了以下代码&#xff…

主成分分析(PCA)Python

实际问题研究中,常常遇到多变量问题,变量越多,问题往往越复杂,且各个变量之间往往有联系。于是,我们想到能不能用较少的新变量代替原本较多的旧变量,且使这些较少的新变量尽可能多地保留原来变量所反映的信…

按配置数据绘制配置型地图marker的icon,自定义marker

一、需求 需要自定义配置数据的marker&#xff0c;其中图片内容要灵活可配置自动生成。此处项目用的百度地图。 效果图&#xff1a; 二、思路 用背景图canvas绘制数字的方式生成icon的图片资源。 再将icon生成对应地图marker。 三、代码 canvasImg.js <!-- * descrip…

进程地址空间(Linux)

进程地址空间 一、引入概念1. 程序的地址分布2. 线性地址和物理地址 二、进程地址空间1. 初步认识2. 地址空间和物理内存的联系3. 区域划分4. 拓展——关于“线” 三、进一步理解进程地址空间四、页表总结 一、引入概念 1. 程序的地址分布 测试代码&#xff1a; #include &l…

Nginx安装以及具体应用

文章目录 Centos7安装NginxNginx命令Nginx具体应用反向代理 location指令说明负载均衡动静分离 Nginx.conf配置详解 Centos7安装Nginx 下载地址&#xff1a;nginx: download 中间这个就是tar.gz包 Centos7安装Nginx 下载nginx-1.16.1.tar.gz上传到Centos7中的/user/local目…

java8 流到底是什么呢?

引入背景&#xff1a; 1、想像写SQL那样操作集合 2、为了提高性能&#xff0c;需要并行处理&#xff0c;并利用多核架构 流到底是什么呢&#xff1f; 流是Java API的新成员&#xff0c;它允许你 以声明性方式处理数据集合&#xff08;通过查询语句来表达&#xff0c;而不是临时…

springboot+vue3组合,对接支付宝付款第一节:内网穿透

springbootvue3组合,对接支付宝付款第一节:内网穿透&#xff01;接下来会为大家展示&#xff0c;使用java的springboot搭建一个简单的后台。提供业务接口。实现在线下单&#xff0c;支付。支付宝付款的案例。 前端页面布局我们使用vue3element-plus来实现绘制。 今天是第一个…

海康实时监控预览视频流接入web

我们采取的方案是后端获取视频流返回给前端&#xff0c;然后前端播放 海康开放平台海康威视合作生态致力打造一个能力开放体系、两个生态圈&#xff0c;Hikvision AI Cloud开放平台是能力开放体系的核心内容。它是海康威视基于多年在视频及物联网核心技术积累之上&#xff0c;…

Jmeter连接数据库报错Cannot load JDBC driver class‘com.mysql.jdbc.Driver’解决

问题产生: 我在用jmeter连接数据库查询我的接口是否添加数据成功时,结果树响应Cannot load JDBC driver class com.mysql.jdbc.Driver 产生原因: 1、连接数据库的用户密码等信息使用的变量我放在了下面,导致没有取到用户名密码IP等信息,导致连接失败 2、jmeter没有JDB…

CodeGPT--(Visual )

GitCode - 开发者的代码家园 gitcode.com/ inscode.csdn.net/liujiaping/java_1706242128563/edit?openFileMain.java&editTypelite marketplace.visualstudio.com/items?itemNameCSDN.csdn-codegpt&spm1018.2226.3001.9836&extra%5Butm_source%5Dvip_chatgpt_c…