扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

Javascript:看这一篇就够了

01/26 14:56
526
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

JavaScript 是现代开发中最重要的语言之一,但零散的知识常让人难以形成体系。本文从核心语法到运行机制,从基础概念到常见难点,系统梳理 JavaScript 的关键知识点,帮助你建立清晰、完整的认知框架。无论入门还是进阶,看完这一篇,理解 JavaScript 就够了。

一、快速开始

众所周知,html、CSS、JS是前端三大知识点。html是骨架,CSS是脸面,JS则是动作。他们三者都是直接在浏览器上运行的语言。因此,我们在调试JS时通常在浏览器上调试。

React、Vue、Angular、Svelte、Bootstrap‌都是JS的前端框架,是它的库。高度集成,开箱则用。

Node.js虽然也是JS的库,但也是一个让 JavaScript 能在浏览器之外运行的运行环境。Node.js 让 JavaScript 不只写网页,还能写服务器和各种工具。

TS (另一门语言,即TypeScript)是 JS 的“加强版”,代码最终都会变成 JS,所有合法的 JS 都是合法的 TS,但需要先编译成 JS,才能在浏览器或 Node.js 中执行。

Javascript 脚本位于html的 <script>与</script>标签之间,我们在这里写代码,来操作浏览器元素(htmlCSS)。右键浏览器,点击检查,一般都可以看到前端代码,也能看到JS脚本。调试时,还可以在上面写程序,来达到知己想要的效果。

1、安装node.js来运行JS脚本

下载安装配置好环境即可,不算复杂(请参阅官方文档):Node.js — Run JavaScript Everywhere

环境配置好后,可在cmd输入node直接进入运行环境

2、使用node.js的工具npm随便安装一些库

打开cmd,如输入以下安装指令,来安装electron库:

npm install electronnpm list electron

electron.js不能使用node指令来运行,因为有些模块(如app模块)只能在 Electron 主进程​ 中使用。

3、使用node运行内置模块

const path = require('path');path.join('folder1', 'folder2', 'file.txt')

特别的,有些内置方法不能再模块里用,如console.log('当前目录:', __dirname);,这是因为node.js是基于 REPL的,__dirname和 __filename是 Node.js 为模块文件注入的局部变量,而 REPL 是全局执行环境,没有模块包装器,因此不存在这些变量。

因此,我们使用node最佳的运行方式是运行一个JS工程或文件,而不是进入内部运行,特别的,使用npm指令也可运行脚本,只不过要配置JSON。

使用node运行脚本时,可以这样(如果其他模块提供命令行运行脚本的方式,则将node替换即可):

node xxx.js

再比如,使用的是electron.js项目,Json中脚本这一块可这样写(如果是node项目,将electron替换成node即可):

"scripts": {  "start": "set NODE_OPTIONS=--no-warnings --trace-warnings && chcp 65001 && electron .", }

附完整JSON:

{  "name": "ElectricFlounder",  "version": "1.0.0",  "description": "",  "author": "",  "main": "src/main/main.js",  "scripts": {    "start": "set NODE_OPTIONS=--no-warnings --trace-warnings && chcp 65001 && electron .",    "build": "electron-builder"  },  "devDependencies": {    "electron": "^29.4.6",    "electron-builder": "^24.9.1"  },  "build": {    "icon": "build/icons/logo.ico",    "extraFiles": [      {        "from": "build/icons/logo.ico",        "to": "resources/build/icons/logo.ico"      }    ]  },  "dependencies": {    "@codemirror/basic-setup": "^0.20.0",    "@codemirror/commands": "^6.10.1",    "@codemirror/language": "^6.11.3",    "@codemirror/search": "^6.5.11",    "@codemirror/state": "^6.5.2",    "@codemirror/view": "^6.39.4",    "chart.js": "^3.9.1",    "monaco-editor": "^0.55.1"  }}

4、网页调试JS

推荐这种方式!新建一个文本,不写入数据,直接改名为test.html :

使用浏览器打开该文件,该文件为空,右侧有打开文件的按钮,打开后显示内容为空

使用文本编辑内容后,前端展示了内容

我们添加JS与CSS,只要点击快速开始就能变化颜色

<!DOCTYPE html><html><head>    <style>        .red { color: red; background: #ffe6e6; padding: 20px; cursor: pointer; }        .green { color: green; background: #e6ffe6; padding: 20px; cursor: pointer; }    </style></head><body>    <div id="quickStart"  onclick="toggleColor()">快速开始</div>        <script>        let isRed = true;                function toggleColor() {            const element = document.getElementById('quickStart');            if (isRed) {                element.className = 'green';            } else {                element.className = 'red';            }            isRed = !isRed;        }    </script></body></html>

5、代码解析

以“快速开始变化颜色”的代码为例,我们来解析一下代码:

(1)HTML解析与DOM构建(渲染前准备)

①DOCTYPE声明:<!DOCTYPE html> 触发浏览器使用标准模式(而不是怪异模式)解析HTML ② 字节流解析:浏览器接收HTML字节流,字符解码器转换为UTF-8字符 ③令牌化(Tokenization):HTML解析器扫描字符,生成开始标签、结束标签、属性、文本等令牌

 <html>开始 → <head>开始 → <style>开始 → CSS文本 → </style>结束 → <body>开始 → <div>开始 → 文本"快速开始" → </div>结束 → <script>开始 → JS文本 → </script>结束

④DOM树构建:令牌送入DOM构建器,创建节点并建立父子关系 • 创建HTMLDocument对象

• 创建html元素节点 → 作为文档根

• 创建head元素节点 → 作为html子节点

• 创建style元素节点 → 放入head

• 创建文本节点(CSS内容) → 放入style

• 创建body元素节点 → 作为html子节点

• 创建div元素节点 → 放入body

• 创建文本节点"快速开始" → 放入div

• 创建script元素节点 → 放入body

• 创建JS文本节点 → 放入script

(2)CSS解析与样式计算(样式准备)

①CSSOM构建:解析<style>标签内容

CSS解析器工作流程:

 .red { color: red; background: #ffe6e6; padding: 20px; cursor: pointer; } ↓ 词法分析:['.red', '{', 'color', ':', 'red', ';', ...] ↓ 语法分析:生成CSSOM规则 ↓ 样式规则对象:{  selector: '.red',  style: {   'color': { value: 'red', priority: '' },   'background': { value: '#ffe6e6', priority: '' },   'padding': { value: '20px', priority: '' },   'cursor': { value: 'pointer', priority: '' }  } }

② 渲染树构建:DOM + CSSOM = 渲染树 • 从DOM根开始遍历

• 对div节点:匹配.red选择器 → 计算样式

• 创建渲染对象(RenderObject/LayoutObject),包含几何信息

(3)JavaScript执行环境初始化(交互能力准备)

①全局执行上下文创建:

 GlobalExecutionContext = {  VariableEnvironment: {   // 预定义的全局对象   window: global,   document: document,   // 你的代码将在下面添加  },  LexicalEnvironment: {...},  ThisBinding: window }

②变量提升阶段: // 扫描代码,提升声明 let isRed; // 提升但不初始化(TDZ开始) function toggleColor() { ... } // 整个函数提升

(4)页面渲染流水线(像素生成)

DOM + CSSOM ↓ 渲染树 (Render Tree) ← 包含可见节点 ↓ 布局 (Layout/Reflow) ← 计算位置尺寸 ↓ 分层 (Layer) ← 创建合成层 ↓ 绘制 (Paint) ← 生成绘制列表 ↓ 栅格化 (Raster) ← 像素填充 ↓ 合成 (Composite) ← 层合并

div的布局计算:

content box: 文本"快速开始"的尺寸 + padding: 20px + border: 0 (默认) + margin: 0 (默认) = 最终渲染矩形

(5)事件系统初始化(交互准备)

①onclick属性解析: • HTML解析器遇到οnclick="toggleColor()"

• 创建属性节点,值为"toggleColor()"

• 在div的扩展属性中存储

②事件监听器注册: // 浏览器内部执行: element.addEventListener('click', function(event) { // 包裹你的代码 toggleColor(); // 调用全局函数 }, false);

③事件流模型建立:

捕获阶段: window → document → html → body → div 目标阶段: div (执行toggleColor) 冒泡阶段: div → body → html → document → window

(6)内存与变量状态(运行时状态)

// 全局变量环境GlobalEnv = { EnvironmentRecord: {  // 编译阶段  isRed: <uninitialized>, // TDZ状态   // 执行阶段  toggleColor: <function object> {   [[Scope]]: GlobalEnv,   [[Code]]: 函数体字节码,   [[FormalParameters]]: [],   [[ThisMode]]: "global"  } }, outer: null}

(7)用户点击事件的完整执行链(核心交互)

物理点击 → 浏览器内核处理  ↓操作系统中断 → 鼠标驱动程序 → 窗口消息循环  ↓浏览器接收WM_LBUTTONDOWN消息  ↓坐标转换:屏幕坐标 → 视图坐标  ↓命中测试 (Hit Testing): 1. 遍历渲染树 2. 检查点(100,100)在哪个渲染对象内 3. 找到div对应的RenderObject  ↓创建事件对象: MouseEvent = {  type: 'click',  target: div元素引用,  clientX: 100,  clientY: 100,  timeStamp: 1234567890 }  ↓事件派发 (Dispatch): // 捕获阶段 window.dispatchEvent(event, CAPTURING_PHASE) document.dispatchEvent(event, CAPTURING_PHASE) ... // 目标阶段 div.dispatchEvent(event, AT_TARGET)  ↓执行监听器: // 查找div的onclick处理器 const handler = div.getAttribute('onclick'); // "toggleColor()"  ↓调用toggleColor():

(8)toggleColor()函数的微观执行

// 1. 创建函数执行上下文toggleColorEC = {  VariableEnvironment: {    element: <uninitialized>,    arguments: { length: 0 }  },  LexicalEnvironment: {    // 闭包相关  },  ThisBinding: window}// 2. 变量初始化element = document.getElementById('quickStart');// document.getElementById的实现://   - 调用Document.getElementById//   - 在DOM树中搜索id="quickStart"//   - 返回第一个匹配的元素引用//   - 内部使用哈希映射加速:document.idMap['quickStart']// 3. 条件判断if (isRed) {  // 读取全局变量  // isRed = true时的执行路径}// 4. className赋值 - 这是最关键的操作!element.className = 'green';

(9)className赋值的底层连锁反应

// 赋值触发一系列操作:element.className = 'green';    ↓// 1. 属性设置器HTMLDivElement.prototype.className.setter('green')    ↓// 2. 更新class属性element.setAttribute('class', 'green')    ↓// 3. 修改DOM属性element._attributes['class'] = 'green'    ↓// 4. 触发样式重新计算element.style = null  // 清除旧计算样式    ↓// 5. 重新匹配CSS规则// 遍历所有样式规则,找到匹配的// .red 不匹配(因为)// .green 匹配!    ↓// 6. 计算新样式StyleResolver.computeStyle(element) {  // 收集所有匹配的规则  // 级联、继承、默认值  return {    color: 'rgb(0, 128, 0)',  // green    background: 'rgb(230, 255, 230)',  // #ffe6e6    padding: '20px',    cursor: 'pointer'  }}    ↓// 7. 标记需要重绘element.renderObject.markForRepaint();    ↓// 8. 触发重排/重绘流程

(10)渲染更新流程(视觉变化)

标记脏区域 (Dirty Rectangle) ↓ 样式重新计算完成 ↓ 布局更新 (Reflow) ↓ 更新图层属性 ↓ GPU命令生成 ↓ VSync信号等待 ↓ 帧提交到GPU ↓ 屏幕扫描输出

关键优化:现代浏览器使用增量布局和合成器线程

主线程: JS执行 → 样式计算 → 布局 ↓ 合成器线程: 分层 → 绘制 → 分块 → 栅格化 ↓ GPU进程: 纹理上传 → 图块合成 → 显示

(11)内存回收与清理

// 函数执行结束 toggleColorEC = null; // 执行上下文可回收

// 变量更新 isRed = false; // 修改全局变量值

// 事件对象清理 MouseEvent = null; // 事件对象可回收

(12)整个流程的CPU指令级视图

用户点击时的大致CPU执行流程1. 中断处理: INT 33h 或 现代中断控制器2. 消息循环: GetMessage → TranslateMessage → DispatchMessage3. 浏览器内核: HandleMouseClick(x, y)4. 事件派发: dispatchEvent5. JS引擎调用:   - 查找toggleColor函数地址   - 准备参数栈   - CALL toggleColor6. toggleColor函数体:   - PUSH 寄存器保存   - 调用getElementById   - 比较isRed值   - JNE/JE 条件跳转   - 设置className属性   - POP 寄存器恢复   - RET

(13)浏览器多进程架构视角

Browser Process ↓ IPC Renderer Process (标签页进程) ├── Main Thread: DOM、样式、JS ├── Compositor Thread: 合成 └── Raster Threads: 栅格化 ↓ IPC GPU Process ↓ 显示器

(14)关键性能优化点

1. 样式计算优化:浏览器维护样式映射表,避免重复计算2. 布局缓存:renderObject缓存几何信息3. 合成层提升:某些CSS属性触发GPU加速4. 事件委托:本示例是直接绑定,实际项目多用事件委托5. 变量访问:isRed是全局变量,访问比局部变量慢

6、关键字

以下是JS的关键字,其中列出了java的一些关键字,对于这些关键字,你不能直接将其作为变量名。之所以列出java的一些关键字,主要原因是JS语法仿照的是java,给大家澄清一下。

类别 关键字 状态 ES版本 说明
实际关键字 break ✅ 可用 ES1 跳出循环或switch
case ✅ 可用 ES3 switch的分支
catch ✅ 可用 ES3 异常捕获
class ✅ 可用 ES6 类声明
const ✅ 可用 ES6 常量声明
continue ✅ 可用 ES1 继续下一次循环
debugger ✅ 可用 ES3 调试器断点
default ✅ 可用 ES3 switch默认分支
delete ✅ 可用 ES1 删除对象属性
do ✅ 可用 ES1 do-while循环
else ✅ 可用 ES1 if的否则分支
export ✅ 可用 ES6 模块导出
extends ✅ 可用 ES6 类继承
false ⚠️ 字面量 ES1 布尔假值
finally ✅ 可用 ES3 最终执行块
for ✅ 可用 ES1 for循环
function ✅ 可用 ES1 函数声明
if ✅ 可用 ES1 条件判断
import ✅ 可用 ES6 模块导入
in ✅ 可用 ES3 属性存在检查
instanceof ✅ 可用 ES3 实例检查
let ✅ 可用 ES6 块级变量
new ✅ 可用 ES1 创建实例
null ⚠️ 字面量 ES1 空值
return ✅ 可用 ES1 函数返回值
static ✅ 可用 ES6 类静态成员
super ✅ 可用 ES6 父类引用
switch ✅ 可用 ES3 多路分支
this ✅ 可用 ES1 当前对象
throw ✅ 可用 ES1 抛出异常
true ⚠️ 字面量 ES1 布尔真值
try ✅ 可用 ES3 异常尝试
typeof ✅ 可用 ES1 类型检查
var ✅ 可用 ES1 变量声明(旧)
void ✅ 可用 ES1 返回undefined
while ✅ 可用 ES1 while循环
with ✅ 可用 ES1 作用域扩展(废弃)
未来保留字 enum  

相关推荐