变量提升底层原理

JS为什么会有变量,今天的东西很干

许多小伙伴对JS变量提升一定不陌生,这个类的题不管是在学校,还是面试都是经常能够遇到的。老师和网上肯定都会说用var 来声明变量,会有一个变量提升,如果在声明之前就用到了这个变量,那这个变量就是undefined

一、V8引擎

1.v8引擎使用c++编写的Google开源高性能Javascript和WebAssembly引擎,它用于Chrome和Node.js等。

2.它实现ECMAScript和WebAssembly,并在Windows7或更高版本,macOS 10.12+和使用x64,IA-32.或者ARM或MIPS处理器的Linux系统上运行

3.V8可以独立运行,也可以嵌入到任何C++应用程序中

这是官方给出的介绍,我们只需要知道:V8引擎是用C++开发的JS和WebAssembly引擎引擎。Chrom浏览器和Node等都是内置了V8引擎,所以JS代码可以在他们的环境中运行

二、V8引擎是如何解析和运行JS代码的

引擎的架构图
在这里插入图片描述

1.parse 代码分析

JS代码在运行之前会有:代码解析,最主要包括有词法分析,和语法分析。

const name = 'Hello'

比如这行代码,V8引擎先进行一个此法分析将代码拆分成:‘const’ ,‘name’,‘=’,‘why’
在这里插入图片描述
在分析的时候会生成一个tokens数组,每一个语句的分析则会放入一个对象当中:
1.const :类型的类型是一个keyword(关键字),他的值是’const’
2.name :类型是一个 identifier(标识符),它的 value 是‘name’
3. name …
4. Hello…
就会这样一个一个的进行解析,解析完成之后,就回生成许多的对象在数组里面,接着又对这些对象进行分析,生成一个AST tree(抽象语法树)
还有一些细节大家可以去看一下:《你不知道的Javascript》这本书,对这个进行了一些讲解,也可以私信我拿电子版的

2.AST(抽象语法树)

https://astexplorer.net/
他家可以通过这个网站看一下代码解析后生成的抽象语法树长什么样子
在这里插入图片描述
实际上当我们使用babel来进行代码转化的时候其实也是先通过解析成抽象语法树后,再把抽象语法树再具体的转化成需要的代码,比如说 ES6 ->ES5,TS -> JS 等等 ,这里我们要说的是 AST -> 字节码

3.Ignition

这是一个V8引擎库, AST(抽象语法树)就是通过这个 ignition 库将AST转化成字节码,然后才运行代码。

(1)为什么要不将 AST(抽象语法树)直接转化成 电脑能够识别的机器语言,而要先转化成字节码呢?

接触过其他语言的都知道,C,C++,Python等等,这些变成编程语言要运行,都要通过编译器编译成计算机能够识别的二进制码,那为什么要不将 AST(抽象语法树)直接转化成 电脑能够识别的机器语言?
因为JS代码运行的环境是不确定的,JS有可能运行再mac的chrom浏览器,也有可能运行再windows,也有可能运行再 linux,也有可能再node的环境下运行的。
那等到这些代码到了不同的平台需要真正运行的时候,V8引擎才将这些字节码转化成对应的汇编码,这样做有一个极大的好处就是:这种方式是可以跨平台的,不依赖于某一个环境。

4.TurboFan

为了做一个优化,TurboFan这个库会将Ignition里面收集到的信息做一个分析,比如一个 sum函数,我们再写一个项目的时候会多次调用,那TurboFan就回将这个函数转化成机器码,来提高代码的运行效率。但是再JS代码中,我们并没有对输入的类型做一个规定,比如

function sum (a,b) {
	return a+b
}

正常情况下我们希望输入的值是Number类型,但是某些原因可能会将“hello”和1传进去,那么再进行优化的时候此时是不符合规矩的,那又会将它返回转化成字节码,这样会浪费一些性能

5.当JS引擎在解析的时候会有一个预解析

在这里插入图片描述

        function add() {
            function sayHello() {
                console.log ('')
            }
            sayHello()
        }

并不是所有的Javascript代码,在一开始就会被执行,那么对所有的JAvascript代码进行解析,必然会影响到网页的运行效率,与解析的作用就是将不必要的函数进行与解析。也就是直接洗暂时需要的内容,而对于函数的全量解析,是在函数被调用时才会进行。在JS引擎解析的时候他只会对add函数进行一个预解析,那现在只要知道这里有一个sayHello函数在add内部就足够了,当需要执行sayHello的时候,再对add函数进行全量解析

6.GlobalObject = {}

        var name = "gss"

        var a = 1
        var b = 2
        var result = a + b

GlobalObject(GO) 是什么呢,他就是在JS引擎执行代码之前,就会在堆内存中创建一个全局变量:Global Object (GO),这个对象所有的作用域都可以访问,里面就有很多JS的内置对象,比如 window,Date ,String等等我们常见的一些内置对象,并且还有一些我们在全局声明的对象

在这里插入图片描述

var GlobalObject = {
            window: GlobalObject,
            Date: {},
            String: {},
            a: undefined,
            b: undefined,
            result: undefined
        }

只有当这些准备好了之后,JS代码,才开始执行,此时代码从上往下执行

       name = "gss"
	   console(name) //"gss"
	   console(a) //undefined
       a = 1
       b = 2
       result = a + b

这就是变量提升

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coder__Song

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值