JavaScript 速查速会
序论
程序运行的本质,就是CPU不断识别并计算出一组指令集(机器码)结果。
使用编译器(如Java),可以事前将特定编程语言编码成中间代码,在编码为机器码,再计算结果。
使用解释器(如JavaScript),则是在‼️程序运行时,逐段读取代码,并直接生成机器码计算结果。
- V8:由 Google 开发的开源 JavaScript 引擎,运行在 Google Chrome 浏览器上。
- Spider Monkey:由 Mozilla 开发的开源 JavaScript 引擎,运行在 Mozilla Firefox 浏览器上。
- Chakra:由 Microsoft 开发的 JavaScript 引擎,运行在 Microsoft Edge 浏览器上。
- JavaScriptCore:由 Apple 开发的 JavaScript 引擎,运行在 Safari 浏览器上。
- Nashorn:由 Oracle 开发的 JavaScript 引擎,运行在 Java SE 8 平台上。
编译步骤
- 词法分析:将文本字符流组织成有意义的词素序列,并转化为词法单元(key,value)序列;并记录到符号表中(符号表记录了每一个变量的名字,及其值、类型、作用域等)
- 语法分析:使用一棵🌲语法树来重新组织词法单元序列,树能够很好地表示这个序列的执行优先级;
- 语义分析:重新检查符号表和🌲语法树是否和约定的编程语言语法一致(比如数组的下标一定要是整数),它同时也收集类型信息存放到符号表中;
- 中间代码生成:完成语义分析后,应当能轻易生成一种类机器的中间代码,并且易于翻译成目标代码(机器码);
- 代码优化:编译器将会改进中间代码
- 目标代码生成;
JavaScript
- JavaScript在1995年由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。1996 年 11 月,网景公司将 JavaScript 提交给 Ecma 国际进行标准化。JavaScript的标准是ECMAScript(European Computer Manufacturers Association 欧洲计算机协会)。截至2012年,所有浏览器都完整的支持ECMAScript 5.1,旧版本的浏览器至少支持ECMAScript 3标准。2015年6月17日,ECMA国际组织发布了ECMAScript的第六版,该版本正式名称为ECMAScript 2015,但通常被称为ECMAScript 6或者ES2015。
- JavaScript 是一门动态语言,动态语言是在运行时确定数据类型的语言。‼️变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型,即变量的类型是由其应用上下文确定的。 对应的静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。
- 2012年10月微软开发的自由和开源的编程语言 TypeScript 宣发。TypeScript 设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。
声明变量,并进行字面量赋值
- 可以使用 let、const、var 声明变量;
- 通过🌻 let 和 const 声明的变量和常量具有块作用域。这意味着它们只在 let 和 const 语句所在的代码块中有定义(如函数、if/while/for 语句等)。
- 使用🌻 var 声明的变量仅仅在函数中具有作用域,如果在函数体外部使用 var ,则会声明全局变量。
- 变量会在函数体中优先在顶部中声明,即变量提升。但 let const 会进入暂存性死区,在声明前使用对应变量将会报错;
变量的类型
- 🌻六种基础类型:number(全局常量 Infinity 和 NaN)、string、boolean、undefined(预定义的全局常量)、null、Symbol;
- 🌻对象类型:如 Array、Set 等都是常见的对象。函数 Function、类 class 是特殊的对象;
- 🌻可以使用 Number、String、Boolean 转换函数将某个字面量显式转化为对应类型;也可以使用 +/- 进行隐式转换;
- Js中的数字采用64位来存储(其中使用 52bit 存储小数点后的精度位,固定 1bit 为小数点前)最大数字为 pow(2, 53) - 1;
类型转换规则
- 🍎对象➡️基础类型:使用 valueOf 函数,如果还是得到对象,将会再使用 toString 函数;
- 🍎基础类型➡️数字:对于 string 空字符串、boolean false、null 都将会转换成 number 0,而非数字的字符串、undefined 都将会转换成 number NaN;
- 🍎基础类型➡️字符串:都会转变为对应字面量的字符串,如 '123'、'false' 等;
- 🍎任意字面量➡️布尔:对于 string 空字符串、number 0 NaN、undefined、null 都将会转换成 boolean false,其他全部都是 true;
运算规则
- 算数:将运算内容均转换为基础数字类型(字符串将会转换成字符串、NaN运算结果始终为NaN)进行运算
- 比较:大小比较将运算内容均转换为数字类型(字符串将会比较字典顺序、NaN比较结果一定为 false)
- 逻辑:将运算内容均转换为基础布尔类型,并返回运算内容(不返回布尔值)
表达式规则(字面量 + 运算符)
- 表达式是字面量 + 运算符的结合,它一定会返回结果;
关于对象
- 对象是一组属性的无序集合;
- 键只能是字符串、数字或者Symbol等简单数据类型;
- 使用字面量 {}、Object.create、new 关键字+函数来创建对象;
👋ES6 中的 Map 对象
1. 键可以是其他数据类型
2. 可以进行迭代、获取长度、展开等
3. 值键对具有顺序性
👋ES6 中的 WeakMap 对象
1. 键只能是对象的引用
2. 当其他地方都不再使用这些引用后,将会释放内存(特别适合临时计算)
👋ES6 中的迭代对象
1. 需要实现 Symbol.Iterable 方法(接口隔离原则)
👋ES6 中的 Proxy 对象
const proxy = new Proxy(target, handlers: { ...get/set })
1. 我们执行代理对象的方法达到操纵对象,而不是直接调用原对象的方法;
2. 代理将会监听整个对象,而不像 Object.defineProperty 需要循环对象属性;
关于函数对象
- 函数是一种特殊的对象,函数实例的 proto 指向 Function 对象;
- 当我们讨论一个 Js 函数,我们就是在讨论它的🌻函数代码,以及围绕函数上下文的🌻所有其他引用;这种函数对象与作用域(即一组变量绑定)组合起来解析函数变量的机制,在计算机科学文献中被称作闭包;
👋对一个函数使用 new 关键字
1. 创建一个空对象;
2. 将构造函数 prototype 指向这个函数;
3. 执行构造函数, 并将新创建的空对象绑定为构造函数的this对象
4. 如果构造函数有返回一个对象,则返回这个对象
👋ES5之前的面向对象
1. 对象的三大特征:封装、继承、多态(面向接口编程);
2. null 具象了 OnlyObject 实例;
3. OnlyObject 实例 new 出了 OnlyFunction 实例;
4. OnlyFunction 实例 new 出了所有 function 函数声明;
5. 通过 new function 可以创建对应对象;通过字面量也可以创建对应对象,但是它没有构造函数;
🌻任意函数,都会在 protptype 上告知 { construct: 构造函数 }
🌻任意实例,都会在 __proto__ 上告知构造函数是谁
👋通过组合而不是继承来设计对象
我们可以使用 Function.apply(target, array) 来使得 Function() 变为 target.Function(),其中的 this 指向 target;通过 apply 我们可以组合任意个工具类对外暴露成一个通用工具类
👋ES2015中的箭头函数,没有 this argument super 关键词,不能使用 new 调用、没有原型;
👋当使用 . 符号运行对象中的函数时,函数中的 this 指向这个对象;另外一种情况则是指向 window;
模块化方案
👋以脚本作为模块
如果不使用 type=module,则脚本的声明将对同一文档中的所有脚本可见
👋以内置 requireJs 划分文件,在执行时动态加载
浏览器中:又名AMD方案,在执行时动态加载模块内容
Node中:又名CommonJs方案,在执行时动态加载模块内容的拷贝
每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。CommonJS 规范规定,每个模块内部,module 变量代表当前模块。这个变量是一个对象,它的 exports 属性(即module.exports)是对外的接口。
👋以 import、export 划分模块,尽可能在编译时提前加载模块内容
加载模块内容的‼️引用,它不会缓存运行结果,而是动态地去被加载的模块取值,并且变量总是绑定其所在的模块
浏览器的运行模型
1. 进程就是程序运行的资源上下文实例,占据独立的内存空间;
2. 可以在进程中再次开辟内存执行线程,这些线程共享一定的资源;
👋主进程:协调页面、网络请求、动画渲染等
👋CPU进程:3D渲染等
👋插件进程
👋渲染进程
1. GUI渲染线程:负责渲染浏览器界面(DOM Tree \ Css Tree => Render Tree,计算布局并绘制),包括界面的小成本重绘(非布局)时或者较大开销的回流(布局)、加载异步资源(视频图片css等)
2. 唯一JS主线程:逐行解析和执行收到的 Javascript 代码。维护一个异步事件队列。当执行 🌻DOM事件🌻定时器🌻网络请求 时将会推入到异步队列,并唤起🌿事件触发线程
3. 事件触发线程:🌿不断得访问事件队列的头部,并将该函数推到执行栈中并立即执行
4. 定时器触发线程
5. 网络请求线程
异步队列包含🌻宿主发起的宏任务(DOM/定时器/网络请求)🌻JavaScript自身发起的微任务(Promise),其中每次微任务;
只有宏/同步线程任务才会导致微任务,一定会清空导致微任务后,才会开始下一个宏任务
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话