深入理解JS | 青训营笔记

32 阅读5分钟

1.JavaScript基本概念

由来

“乘众人之智,合众人之力”

1.借鉴了c语言的基本语法

2.借鉴Java语言的数据类型和内存管理

3.借鉴Scheme语言,将函数提升到“第一公民”的地位

4.借鉴Self语言,使用基于prototype的继承机制

发展历程

1.Mocha->1995.9LiveScript—->1995.12JavaScript

2.1997年6月,第一版ECMAScript发布

3.1999年12月,第三版ECMAScript发布

4.2009年12月,第五版ECMAScript发布

5.2009年,Ryan创建了Node.js

6.2010年,Isaac基于node.js写出了npm

7.2015年6月,第六版ECMAScript发布

数据类型

JavaScript的数据类型分为2类,一类是对象,包括了数组和函数等等;另一类的基础数据类型,包括了string,undefined,number,null,symbol,biglnt boolean。

Snipaste_2023-05-14_21-46-13.jpg

作用域

作用域是指变量和函数的可访问范围。在JavaScript中,有以下三种作用域

Snipaste_2023-05-14_21-49-21.jpg 1.全局作用域:指的是定义在代码顶部的变量和函数,在整个程序中都可以被访问。

2.函数作用域:顾名思义是由函数定义的变量和函数,只在函数内部访问。

3.块级作用域:指的是由一对花括号{}包裹起来的语句块中定义的变量,只能在该语句块内部被访问。

变量提升

在JavaScript中,执行上下文时变量和函数声明会被提升到作用域顶部,这意味着在代码执行之前,js引擎会先扫描代码并将变量声明和函数声明提升到它们所在作用域的顶部,从而可以在声明前使用这些变量和函数。

1.var声明的变量会被提升到函数或全局作用域的顶部并初始化为undefined。

2.函数声明会被提升到函数或全局作用域的顶部,并可以在声明前调用。

3.let 和 const声明的变量则不会被提升,因而它们不能在声明前使用

2.JavaScript是怎么执行的

概括

Snipaste_2023-05-14_22-28-06.jpg 首先原生的JavaScript代码用通过解析器解析后,生成抽象语法树(AST)和执行上下文,解释器根据AST生成字节码。最后在执行字节码的过程当中,如果发现有热代码(被重复执行多次的一段代码就称为热代码)。那么后台的优化编译器 就会把这段热点字节码编译为高效的机器码。如果当再次执行这段被优化的代码时,只需要执行编译后的机器码就可以了,这样就大大提升了代码的执行效率。

生成AST两个阶段

1.词法解析:又称为分词,由词法解析器完成,其作用就是将一行行的源码拆解成一个个token。
所谓token指的是语法上不可能再分的、最小的单个字符或字符串。

如const company ="Bytedance";可以解析成关键字const,标识符company,赋值运算符=,字符串Bytedance四个token

2.语法分析:又称解析,是由语法分析器完成的,其作用是将上一步生成的 token 数据,根据语法规则转化为AST。按照逻辑结构 验证语法 生成树形结构对源码进行校验,如果源码符合语法规则,这一步就会顺利完成,但如果源码存在语法错误,这一步就会终止,并抛出错误。

ignition

上一步完成以后,ignition根据AST的结构生成字节码文件,并解释执行字节码。

TuiboFan

进入执行阶段:如果有一段第一次执行的字节码,解释器 Ignition 会逐条解释执行。在执行字节码的过程中,如果发现有热代码,那么TurboFan 会把该段热点的字节码编译为高效的机器码,然后当再次执行这段被优化的代码时,只需要执行编译后的机器码即可

3.JavaScript中的闭包

概念

闭包是指函数与其周围的状态的组合。即定义在函数内部的函数,并且可以访问外部函数中声明的变量和参数,即使在外部函数被调用完毕以后依然有效。

组成

闭包由两部分组成:一个是函数体,另一个是创建该函数的环境。当函数返回时,它会将自己和它所引用的变量打包起来形成一个闭包。

实例

微信图片_20230514230808.jpg

在这个例子中,outerFunction 是外部函数,它定义了一个局部变量count和一个内部函数innerFunction。在outerFunction的最后,它返回并暴露了innerFunction。因此,在执行const increment = outerFunction()后,increment 就变成了innerFunction。由于innerFunction在其词法环境中引用了count,所以在每次调用increment()时,innerFunction都可以访问并修改count,即使outerFunction已经返回并退出。这就是闭包的本质。

使用场景

常用于实现一些高级的应用程序模式,比如函数工厂、模块模式等等。通过使用闭包,在当前作用域范围外部保存一个内部函数的引用,可以实现对该函数私有变量的访问和修改,同时又不会污染全局作用域。

注意

谈到闭包一定逃不了内存问题。闭包会保留它们引用的变量,所以滥用闭包会导致内存占用过多,影响程序性能。