JavaScript 之 作用域变量提升闭包

news2024/11/16 15:52:49

一、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.coloradmin.cn/o/1415192.html

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

相关文章

Django介绍

一、介绍 Django是Python语言中的一个Web框架,Python语言中主流的web框架有Django、Tornado、Flask 等多种 优势:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等功能,是一个全能型框架,拥有自己的Admin数据管理后台,第三方工具齐全,性能折中 缺点:…

用ChatGPT写申请文书写进常春藤联盟?

一年前,ChatGPT 的发布引发了教育工作者的恐慌。现在,各大学正值大学申请季,担心学生会利用人工智能工具伪造入学论文。但是,聊天机器人创作的论文足以骗过大学招生顾问吗? ChatGPT简介 ChatGPT,全称聊天生…

C++:引用

目录 概念: 引用的使用格式: 引用特性: 常引用 使用场景: 1、做参数 二级指针时的取别名 一级指针取别名 一般函数取别名 2、做返回值 函数返回值的原理: 引用的返回值使用: 引用和指针的对比&…

基于 SpringBoot+Vue 的免税商品商城系统的研究与实现

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

免费电视TV盒子软件,好用的免费电视盒子软件大全,免费电视盒子APP大全,2024最新整理

1、TVbox下载地址、影视接口、配置教程 下载地址 TVbox TVbox可用接口地址合集 注:接口均来源于互联网收集分享!所有接口都是经过测试的,如果出现加载失败等情况,可能是因为接口针对的盒子有兼容问题,可以多试试几…

(七)springboot实战——springboot3集成R2DBC实现webflux响应式编程服务案例

前言 本节主要内容是关于使用新版springboot3集成响应式数据库R2DBC,完成响应式web服务案例。需要注意的是,此次项目使用的JDK版本是JDK17,springboot版本使用3.2.2版本,数据库使用关系型数据库mysql。WebFlux 是一个基于响应式编程模型的框…

redis过期事件监听、可以做延时任务 第二篇(简单)

在使用redis时,所有的key都要设置过期时间,过期之后,redis就会把对应的key清除掉。 此方法可以监听redis的key失效,在失效时做一些逻辑处理 redis过期监听 不像mq有保证 不推荐用来弄需要有保证的业务 现象: redis …

P1045 [NOIP2003 普及组] 麦森数题解

题目 形如的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P3021377,它有909526位。麦森数有许多重要应用,它与…

Linux版本下载Centos操作

目录 一、Centos7 二、下载Centos7镜像 三、下载Centos7 买了个硬件安装裸机(一堆硬件) 把安装盘放到虚拟机里面,给机器加电 配置设置 ​编辑 网络配置 开启网络功能 四、安装linux客户端 Xshell是什么 Xshell使用(连接…

GLog开源库使用

Glog地址:https://github.com/google/glog 官方文档:http://google-glog.googlecode.com/svn/trunk/doc/glog.html 1.利用CMake进行编译,生成VS解决方案 (1)在glog-master文件夹内新建一个build文件夹,用…

Java笔记 --- 二、Stream流

二、Stream流 结合Lambda表达式,简化集合、数组的操作 获取Stream流对象 单列集合获取Stream流 双列集合获取Stream流 数组获取Stream流 一堆零散的数据获取Stream流 Stream流的静态方法of的形参是一个可变参数,可以传递零散数据,也可以传递…

Scrapy IP()类 编程指南(基础)

Scrapy IP()类 编程指南(基础) IP简介 工欲善其事,必先利其器,在聊Scapy IP类时,我们先要了解IP是什么。 IP指的是Internet Protocol(互联网协议)的数据包。Internet Protocol是互联网上用于在…

超简单的正则表达式从入门到精通

正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。 概念 正则表达式是对字…

使用Promethues+Grafana监控Elasticsearch

PromethuesGrafana监控Elasticsearch 监控选用说明指标上报流程说明实现监控的步骤搭建elasticsearch-exporter服务搭建promethues和grafana服务 监控选用说明 虽然用Kibana来监控ES,能展示一些关键指标,但ES本身收集的指标并不全面,还需要在…

Qt : Style Sheet

When a style sheet is active, the QStyle returned by QWidget::style() is a wrapper “style sheet” style, not the platform-specific style. The wrapper style ensures that any active style sheet is respected and otherwise forwards the drawing operations to t…

Centos9使用chrony服务同步时间

安装chrony命令 Centos9里是预安装的,没有安装的话执行以下命令: yum install -y chronyCentos9 时间同步要使用chrony命令,ntp命令没有了 查看状态 #启用chronyd服务 systemctl enable chronyd#重启chronyd服务 systemctl restart chron…

【Docker】nacos集群搭建Nginx负载均衡

目录 一、mysql安装与基操 1.1 数据准备 1.2 创建mysql与数据表 二、Nacos集群部署 2.1 创建nacos及配置 2.2 创建Nginx容器 一、mysql安装与基操 1.1 数据准备 拉取mysql docker pull mysql:5.7(版本) 定义挂载目录 mkdir -p /mysql/{conf,data,script} 配置my.c…

金盘移动图书管理系统doUpload.jsp接口存在文件上传漏洞

指纹特征 app"金盘软件-金盘移动图书馆系统"漏洞复现 POST /pages/admin/tools/uploadFile/doUpload.jsp HTTP/1.1 Host: User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0 Accept: text/html,application/xhtmlxm…

LLM - Transformer 的 Q/K/V 详解

目录 一.引言 二.传统 Q/K/V 三.Transformer Q/K/V - Input Query - Q/K/V 获取 - Q/K 相似度计算 - 注意力向量 - Multi Head 四.代码测试 - 初始化 - Attention - Main 五.总结 一.引言 Transformer 的输入是我们的一个 query 句子,例如 "我爱…

二叉搜索树,穷举(全排列)

力扣230.二叉搜索树中第K小的元素 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeN…