JavaScript & Web 前端关键知识总结
一、DOM(文档对象模型)
1. DOM 结构
- 定义:DOM 是文档对象模型,将 HTML 或 XML 文档表示为可编程对象的树结构。
- 树形结构:HTML 文档被解析为节点树,每个节点代表文档的一部分(元素、属性、文本等)。
- 节点类型:
-
Element:表示 HTML 元素Text:表示文本内容Document:表示整个文档Comment:表示注释
示例:
<html>
<body>
<div id="main">
<p>Hello World</p>
</div>
</body>
</html>
树结构表示:
Document
└── html
└── body
└── div#main
└── p
└── Text: "Hello World"
2. 常用 DOM 操作
- 访问节点:
-
document.getElementById("main"):通过 ID 访问元素document.querySelector(".class"):通过 CSS 选择器访问第一个匹配的元素document.querySelectorAll("p"):通过 CSS 选择器访问所有匹配的元素
- 创建节点:
-
document.createElement("div"):创建新的元素节点document.createTextNode("Hello"):创建新的文本节点
- 修改节点:
-
element.appendChild(newElement):将新的子节点添加到现有节点element.removeChild(childElement):从现有节点中移除子节点element.replaceChild(newElement, oldElement):用新节点替换子节点element.innerHTML = "<p>New Content</p>":设置 HTML 内容
示例:
const div = document.createElement("div");
div.textContent = "Hello World";
document.body.appendChild(div); // 添加到 body
二、闭包(Closure)
1. 概念
- 定义:闭包是指有权访问另一个函数作用域中的变量的函数,即使外部函数已经返回,闭包依然可以访问和修改外部函数的变量。
- 作用:闭包用于数据的私有化和延迟执行。
2. 特性
- 数据封装:通过闭包,可以创建带有私有数据的函数。
- 持久化状态:闭包可以记住其创建时的作用域中的变量值。
3. 使用场景
- 函数工厂:生成不同的函数,每个函数有其独立的作用域。
- 模块化:模拟私有方法和属性。
4. 示例
function outer() {
let count = 0; // 外部变量
return function inner() { // 内部函数
count++; // 访问外部变量
return count;
};
}
const increment = outer(); // 创建闭包
console.log(increment()); // 1
console.log(increment()); // 2
三、TypeScript 静态类型系统
1. 优势
- 类型检查:在编译时检查类型错误,减少运行时错误。
- 代码提示:提供智能补全和文档提示,提高开发效率。
- 代码可读性:明确变量、函数的预期类型,提高代码可读性。
2. 基本类型
- 原始类型:
number,string,boolean,symbol,null,undefined - 对象类型:
object,array,function - 特殊类型:
any,void,unknown,never
3. 自定义类型
- 接口(
interface) :定义对象的结构 - 类型别名(
type) :定义类型别名或联合类型
let num: number = 42;
let str: string = "hello";
interface Person {
name: string;
age: number;
}
const person: Person = { name: "John", age: 30 };
type ID = number | string;
let userId: ID = 123; // or "abc"
4. 泛型(Generics)
- 定义:泛型提供了一种在定义函数、接口或类时不指定具体类型,而在使用时指定类型的方法。
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("Hello"); // 使用时指定类型
四、Git 及其工作流
1. 基本概念
- 版本控制:管理文件的更改历史,允许多用户协作开发。
- 分支(Branch) :并行开发不同功能,保持代码稳定性,通过分支进行新功能开发和测试。
2. 常用命令
- 初始化和克隆:
-
git init:初始化新的 Git 仓库git clone <url>:克隆远程仓库
- 更改管理:
-
git add <file>:将更改添加到暂存区git commit -m "message":提交更改
- 分支操作:
-
git branch <branch>:创建新分支git checkout <branch>:切换分支git merge <branch>:合并分支
- 同步操作:
-
git pull:拉取远程更新并合并git push:推送本地更改到远程
git init
git add .
git commit -m "Initial commit"
3. Rebase
- 定义:
git rebase将一个分支上的更改应用到另一个分支上,以创建一个清晰的历史记录。 - 用途:保持历史记录线性和整洁,避免合并冲突。
git checkout feature
git rebase main
五、Promise 及其异常捕获机制
1. 概念
- 定义:Promise 是表示异步操作最终完成或失败的对象。
- 状态:
-
pending:进行中fulfilled:已成功rejected:已失败
2. 使用方法
then:处理成功结果catch:处理错误finally:无论成功与否都会执行
3. 异常捕获
- 在 Promise 链中:
catch可以捕获链中发生的任何错误。 - 在
async/await:使用try...catch捕获异常。
new Promise((resolve, reject) => {
resolve("Success");
})
.then(value => console.log(value))
.catch(error => console.error(error))
.finally(() => console.log("Done"));
async function fetchData() {
try {
let response = await fetch("url");
let data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
} finally {
console.log("Fetch complete");
}
}
fetchData();
六、重排(Reflow)与重绘(Repaint)
1. 重排(Reflow)
- 定义:重新计算元素的几何结构(尺寸、位置等)。
- 触发条件:元素尺寸、位置变化、DOM 变动、窗口大小改变等。
element.style.width = "100px"; // 触发重排
- 代价:重排代价高,需要重新计算布局和渲染树。
2. 重绘(Repaint)
- 定义:重新绘制元素的外观(颜色、背景、边框等)。
- 触发条件:元素的颜色、背景图、文字颜色等变化。
element.style.backgroundColor = "red"; // 触发重绘
- 代价:重绘比重排代价低,但频繁重绘也会影响性能。
3. 优化策略
- 减少 DOM 操作:合并多次修改,减少频繁操作 DOM。
- 使用
documentFragment:在内存中操作,最后一次性添加到 DOM。 - 批量操作 CSS 类:替代逐一设置内联样式。
七、JavaScript 事件机制
1. 事件传播
- 捕获阶段:从祖先到目标,检查事件是否应该触发。
- 目标阶段:事件到达目标元素,执行事件处理函数。
- **冒泡阶段
**:从目标回到祖先,允许祖先元素处理事件。
2. 事件处理方法
- HTML 属性:在 HTML 标签中直接定义事件。
<button onclick="handleClick()">Click me</button>
- DOM 0 级:直接给元素的事件属性赋值。
element.onclick = handleClick;
- DOM 2 级:使用
addEventListener添加事件监听器,支持事件冒泡和捕获。
element.addEventListener("click", handleClick);
3. 阻止事件传播
- 阻止冒泡:
event.stopPropagation(),阻止事件向上冒泡。 - 阻止默认行为:
event.preventDefault(),阻止默认事件行为。
element.addEventListener("click", function(event) {
event.stopPropagation(); // 阻止冒泡
event.preventDefault(); // 阻止默认行为
});
4. 事件委托
- 定义:将事件监听器添加到父元素,通过检查
event.target判断事件目标,减少事件监听器数量。 - 优势:提升性能,减少内存使用。
parentElement.addEventListener("click", event => {
if (event.target.matches("li")) {
console.log("LI clicked");
}
});
八、JavaScript 事件循环
1. 执行栈
- LIFO 结构:管理函数调用顺序,即后进先出。
- 作用:控制同步任务的执行顺序。
2. 事件循环步骤
- 执行同步代码:所有同步任务都在主线程上执行,形成一个执行栈。
- 处理微任务队列:同步任务完成后,处理微任务(Promise 回调、
MutationObserver等)。 - 处理宏任务队列:处理宏任务(
setTimeout,setInterval,I/O回调等)。
3. 宏任务和微任务
- 宏任务:
setTimeout,setInterval,I/O,UI Rendering - 微任务:
Promise.then,MutationObserver
console.log("start");
setTimeout(() => {
console.log("setTimeout");
}, 0);
Promise.resolve().then(() => {
console.log("promise");
});
console.log("end");
// 输出顺序: start, end, promise, setTimeout
4. 异步任务处理
- 宏任务:常用于计时器、异步 I/O 操作。
- 微任务:用于立即执行的异步任务。
setTimeout(() => console.log("Timer"), 0);
Promise.resolve().then(() => console.log("Promise"));