本总结基于《疯狂HTML+CSS+JS》一书,结合现代JavaScript特性,对JavaScript核心知识点进行全面梳理。
1. JavaScript语法
1.1 执行js代码
javascript:alert('执行js');一般放在超链接中,用户点击即执行。
<script>
alert("执行js");
</script>
1.2 变量赋值
var a = 1; // 显式声明
let b = 2; // ES6 块级作用域变量
const c = 3; // ES6 常量
1.3 全局变量与局部变量
var scope = "全局变量";
function test() {
alert(scope); // undefined (变量提升)
var scope = "局部变量";
alert(scope); // 局部变量
}
// ES6 块级作用域
function testES6() {
let scope = "局部变量";
if (true) {
let scope = "块级变量";
console.log(scope); // 块级变量
}
console.log(scope); // 局部变量
}
1.4 浮点数
var a = 0.333;
var b = a * 5;
alert(b); // 1.665
在js中判断浮点数是否相等,建议判断两者的差值是否小于一个足够小的数(例如0.0000000000001)。
1.5 字符串
js中没有字符类型变量,”” 与 ‘’ 一致。
var s = "abcdefg";
b = s.slice(3, -1); // "def"
// ES6 模板字符串
let name = "John";
let greeting = `Hello, ${name}!`;
1.6 字符串的正则表达式方法
match()返回匹配的字符串(数组或null),可加/g进行全局匹配search()返回匹配的索引值(单个)replace()替换匹配的字符串,默认只替换第一个匹配项;使用正则表达式/g标志可替换所有匹配项split()根据正则表达式分割字符串
1.7 undefined和null
null == undefined; // true
null === undefined; // false
undefined 表示变量已声明但未初始化,null表示变量被显式设置为空值。
1.8 运算符
// 逗号运算符 依次计算每个表达式,并返回最后一个表达式的值
a = ((b = 5), (c = 7), (d = 56)); // a = 56
a = void ((b = 5), (c = 7), (d = 56)); // a = undefined
// ES6 扩展运算符
let arr1 = [1, 2, 3];
let arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// 解构赋值
let { x, y } = { x: 1, y: 2 };
1.9 typeof和instanceof
typeof "123"; // "string"
typeof 123; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (历史遗留问题)
typeof {}; // "object"
typeof []; // "object"
typeof function () {}; // "function"
// instanceof 判断对象是否为某构造函数的实例
var a = [4, 5];
alert(a instanceof Array); // true
1.10 语句
抛出异常
throw new Error("用户自定义异常");
try {
// 可能出错的代码
} catch (e) {
alert(e.message); // "用户自定义异常"
} finally {
// 无论是否出错都会执行的代码
}
Error对象
JavaScript内置Error对象,包含message和name属性。
try {
throw new Error("出错了", "错误原因");
} catch (e) {
console.log(e.message); // "出错了"
console.log(e.name); // "Error"
console.log(e.stack); // 错误堆栈信息
}
自定义错误类型
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
try {
throw new ValidationError("输入不合法");
} catch (e) {
if (e instanceof ValidationError) {
console.log("验证错误:", e.message);
} else {
throw e;
}
}
for in 循环
// 遍历对象属性
for (let prop_name in navigator) {
console.log(prop_name + ": " + navigator[prop_name]);
}
// ES6 for of 循环
for (let value of [1, 2, 3]) {
console.log(value);
}
1.11 函数
js 允许先调用函数再定义函数(函数提升)。
定义函数
var show_name = function (name) {
alert(name);
};
show_name("K"); // K
// ES6 箭头函数
const showName = name => {
alert(name);
};
函数即对象
var hello = function () {
/* ... */
};
console.log(hello instanceof Function); // true
console.log(hello instanceof Object); // true
console.log(hello.toString()); // 输出函数源代码
调用函数方式的不同
- 直接调用函数:返回return的值或undefined
- new 函数名():得到的是对象实例
this关键字
- 在函数中使用
this变量,该变量指向函数的调用者 - 函数可作为对象的方法调用,如没有指定调用者,则在非严格模式下
this默认指向 window对象(浏览器环境),严格模式下指向undefined
var hello = function () {
/* ... */
};
window.hello();
var p = {
work: function () {
/* ... */
},
};
p.work();
// ES6 箭头函数中的this
const obj = {
name: "John",
sayHello: function () {
setTimeout(() => {
console.log(this.name); // 箭头函数不绑定自己的this,继承外部上下文的this
}, 1000);
},
};
obj.sayHello(); // 1秒后输出: John
函数中的变量
function Person() {
// 局部变量 只能在函数里访问
var id;
// 实例属性 通过对象.访问
this.age;
// 类属性 通过Person.name访问
Person.name;
}
动态添加属性和方法
JavaScript是一种动态语言,能随时给对象增加属性和方法。
function Student(name) {
this.name = name; // 实例属性
}
var student = new Student("K");
// 动态增加实例属性
student.age = 22;
alert(student.age); // 22
// 动态增加实例方法
student.sayHello = function () {
console.log(`Hello, I am ${this.name}`);
};
student.sayHello(); // Hello, I am K
// 动态增加静态属性(通过构造函数)
Student.MAX_AGE = 100;
alert(Student.MAX_AGE); // 100
调用函数的三种方式
- 直接调用
window.alert();
// 或
alert();
- call()调用
var each = function (array, fn) {
for (var index in array) {
// null表示以window为调用者
fn.call(null, index, array[index]);
}
};
each([4, 20, 3], function (index, ele) {
alert("第 " + index + " 个元素是 : " + ele);
});
- apply()调用
var myfun = function (a, b) {
alert(a + " " + b);
};
myfun.call(window, 12, 23); // 12 23
myfun.apply(window, [20, 39]); // 20 39
// 使用 ES6 spread operator 直接传参
myfun(...[10, 20]); // 10 20
// 使用 apply 配合 arguments 对象
var example = function (num1, num2) {
myfun.apply(this, [num1, num2]); // 传入实际参数
};
example(20, 40); // 20 40
函数的独立性
在函数A中可以定义函数B,但是函数B还是独立于函数A。
参数传递方式
JavaScript中所有参数都是按值传递的。但需要注意:
- 基本类型:传递的是值的副本,修改不会影响原变量
- 引用类型:传递的是对象引用的副本,所以修改对象的属性会影响原对象
基本类型:
function change(arg) {
arg = 10;
alert(arg); // 10
}
var x = 5;
alert(x); // 5
change(x);
alert(x); // 5
复合类型:
function change(person) {
person.age = 10;
alert(person.age); // 10
person = null;
}
var person = { age: 5 };
alert(person.age); // 5
change(person);
alert(person.age); // 10
console.log(person); // {age: 10}
可选参数与默认参数
JavaScript函数不检查参数数量,少传的参数为undefined。
function text(person) {
alert(typeof person); // undefined
}
text(); // undefined
// ES6 默认参数
function greet(name = "Guest") {
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Guest!
greet("John"); // Hello, John!
对象属性遍历
JavaScript对象可以像关联数组一样访问属性。
function Person(name) {
this.name = name;
this.info = function () {
alert(this.name);
};
}
var person = new Person("K");
// 遍历person属性
for (let propName in person) {
console.log(person[propName]);
}
继承和prototype
使用prototype实现继承:
function Person() {}
var person = new Person();
// 添加原型方法
Person.prototype.work = function () {
console.log("Working...");
};
person.work(); // OK
// ES6 Class
class PersonES6 {
constructor(name) {
this.name = name;
}
info() {
console.log(this.name);
}
}
class Student extends PersonES6 {
constructor(name, grade) {
super(name);
this.grade = grade;
}
}
1.12 创建对象三种方式
new关键字调用构造器创建对象
function Person(name) {
this.name = name;
}
var person_1 = new Person();
var person_2 = new Person("K");
使用Object直接创建对象
var my_obj = new Object();
my_obj.name = "K";
my_obj.handsome = function () {
/* ... */
};
对象字面量(JSON)创建对象
var person = {
name: "K",
school: ["ChangAn", "TianJin"],
girl_friends: [
{
name: "Haski",
age: 11,
},
{
name: "Samoyed",
age: 8,
},
],
};
alert(person.girl_friends[0].name); // Haski
// ES6 简洁对象字面量
const name = "John";
const age = 30;
const personES6 = {
name,
age,
greet() {
console.log(`Hello, ${this.name}!`);
},
};
2. DOM编程
DOM操作其实JQuery已经做得很好了,这里简单补充一下原生JS的知识。
2.1 访问HTML元素
- 通过id或name:
getElementById('id')或getElementsByName('name') - 根据节点关系:
node.parentNode; // 返回父节点
node.previousSibling; // 返回前一个兄弟节点
node.nextSibling; // 返回后一个兄弟节点
node.childNodes; // 返回当前节点的所有子节点
node.getElementsByTagName("标签名称"); // 返回当前节点具有指定标签的子节点
// 现代DOM API
node.querySelector(selector); // 返回第一个匹配的元素
node.querySelectorAll(selector); // 返回所有匹配的元素
2.2 创建HTML元素
const element = document.createElement("div");
element.textContent = "Hello";
// 复制节点
const clone = element.cloneNode(true); // true表示深拷贝
2.3 添加节点
parent.appendChild(node); // 添加为当前节点的最后一个子节点
parent.insertBefore(newNode, refNode); // 在refNode前添加newNode
parent.replaceChild(newChild, oldChild); // 替换节点
2.4 删除节点
parent.removeChild(oldNode);
// 现代API
node.remove();
2.5 window对象
// 导航
window.location.href = "https://www.example.com";
window.history.back();
// 屏幕信息
console.log(window.screen.width);
console.log(window.screen.height);
// 对话框
window.alert("Message");
const result = window.confirm("Are you sure?");
const input = window.prompt("Enter your name:");
// 定时器
const timer = setInterval(() => {
console.log("Hello");
}, 1000);
clearInterval(timer);
2.6 navigator和地理位置
// 浏览器信息
console.log(navigator.userAgent);
// 地理位置
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
position => {
console.log(position.coords.latitude, position.coords.longitude);
},
error => {
console.error(error);
}
);
}
3. 事件处理机制
3.1 常见事件
- click:点击
- mouseover/mouseout:鼠标指针进入/离开元素(会冒泡)
- mouseenter/mouseleave:鼠标指针进入/离开元素(不冒泡)
- keydown/keyup:键盘按下/松开
- submit:表单提交
- load:页面加载完成
- resize:窗口大小改变
3.2 事件处理和this
const p = {
name: "John",
info: function () {
alert(this.name);
},
};
document.getElementById("bt").onclick = p.info; // this指向'bt'控件
document.getElementById("bt").onclick = () => p.info(); // this指向p
3.3 DOM事件监听
// 添加事件监听器
element.addEventListener("click", function (event) {
console.log("Clicked!");
});
// 阻止事件传播
element.addEventListener("click", function (event) {
event.stopPropagation();
});
// 取消默认行为
element.addEventListener("click", function (event) {
event.preventDefault();
});
// 事件委托
parentElement.addEventListener("click", function (event) {
if (event.target.matches(".child")) {
console.log("Child clicked!");
}
});
4. 本地存储与离线应用
4.1 Web Storage
使用理由:Cookie的局限性
- Cookie大小被限制为4KB
- Cookie会包含在每次HTTP请求中
- Cookie如未设置Secure标志,在HTTP传输中为明文
Web Storage有两种:
- Session Storage:生命周期与用户Session一致
- Local Storage:保存在用户的磁盘中,需要手动删除
// 存储数据
localStorage.setItem("name", "John");
sessionStorage.setItem("token", "abc123");
// 读取数据
const name = localStorage.getItem("name");
// 删除数据
localStorage.removeItem("name");
// 清除所有数据
localStorage.clear();
// 存储对象
const user = { name: "John", age: 30 };
localStorage.setItem("user", JSON.stringify(user));
const storedUser = JSON.parse(localStorage.getItem("user"));
4.2 构建离线应用
使用Service Worker实现离线缓存:
// 注册Service Worker
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/sw.js")
.then(registration => {
console.log("Service Worker registered:", registration);
})
.catch(error => {
console.error("Service Worker registration failed:", error);
});
}
5. 使用worker创建多线程
5.1 Worker简介
Worker中无法使用DOM、alert等与界面有关的操作,也无法访问window对象的属性,但可以使用console.log、setTimeout等API,以及发送消息与主线程通信。
5.2 主线程与Worker通信
// 主线程
const worker = new Worker("worker.js");
// 发送消息给Worker
worker.postMessage({ start: 1, end: 100 });
// 接收Worker的消息
worker.onmessage = function (event) {
console.log("Received from worker:", event.data);
};
// 处理Worker的错误
worker.onerror = function (error) {
console.error("Worker error:", error.message);
};
// 关闭Worker
worker.terminate();
// worker.js 内容示例
/*
self.onmessage = function (event) {
const { start, end } = event.data;
const primes = findPrimes(start, end);
self.postMessage(primes);
};
function findPrimes(start, end) {
const primes = [];
for (let i = start; i <= end; i++) {
if (isPrime(i)) primes.push(i);
}
return primes;
}
function isPrime(num) {
if (num < 2) return false;
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) return false;
}
return true;
}
*/
5.3 Worker应用场景
Worker适用于计算密集型任务,如图像处理、数据加密、大数据排序等,可以避免阻塞主线程。
6. 客户端通信
6.1 跨文档通信
// 发送消息
const targetWindow = window.open("https://example.com");
targetWindow.postMessage("Hello", "https://example.com");
// 接收消息
window.addEventListener("message", function (event) {
if (event.origin !== "https://example.com") return;
console.log("Received message:", event.data);
event.source.postMessage("Reply", event.origin);
});
6.2 WebSocket与服务器通信
const socket = new WebSocket("ws://localhost:3000");
socket.onopen = function () {
console.log("Connected to server");
socket.send("Hello Server");
};
socket.onmessage = function (event) {
console.log("Received:", event.data);
};
socket.onclose = function () {
console.log("Disconnected from server");
};
socket.onerror = function (error) {
console.error("WebSocket error:", error);
};
7. 现代JavaScript特性
7.1 ES6+ 新特性
- let/const:块级作用域变量和常量
- 箭头函数:更简洁的函数语法
- 模板字符串:支持多行字符串和变量插值
- 解构赋值:从对象或数组中提取值
- 默认参数:函数参数默认值
- 剩余参数:处理不定数量的参数
- 扩展运算符:展开数组或对象
- Promise:处理异步操作
- async/await:更简洁的异步代码
- Class:面向对象编程
- Module:模块化
7.2 异步编程
// Promise
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
// async/await
async function getData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
getData();
7.3 模块化
// 导出
// module.js
export const name = "John";
export function greet() {
console.log("Hello!");
}
const user = {
age: 30,
city: "New York",
};
export default user;
// 导入
// main.js
import { name, greet } from "./module.js";
import user from "./module.js";
console.log(name); // John
greet(); // Hello!
console.log(user.age); // 30
7.4 重要数据结构
Symbol
Symbol是ES6新增的原始数据类型,表示唯一的标识符,常用于对象属性的键。
const sym = Symbol("description");
const obj = {
[sym]: "value",
};
console.log(obj[sym]); // value
// Symbol的唯一性
const s1 = Symbol("id");
const s2 = Symbol("id");
console.log(s1 === s2); // false
// 常用的内置Symbol
const iterator = Symbol.iterator;
console.log(typeof iterator); // symbol
Set
Set是ES6新增的数据结构,类似于数组,但所有元素都是唯一的。
const set = new Set([1, 2, 3, 2, 1]);
console.log(set.size); // 3
console.log([...set]); // [1, 2, 3]
// 添加和删除元素
set.add(4);
set.delete(2);
console.log(set.has(2)); // false
// 遍历
for (const item of set) {
console.log(item);
}
Map
Map是ES6新增的数据结构,类似于对象,但键可以是任意类型。
const map = new Map();
map.set("name", "John");
map.set(123, "number key");
map.set(true, "boolean key");
console.log(map.get("name")); // John
console.log(map.size); // 3
// 使用对象作为键
const objKey = { id: 1 };
map.set(objKey, "object value");
console.log(map.get(objKey)); // object value
// 遍历
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
WeakSet和WeakMap
WeakSet和WeakMap是弱引用版本,适用于临时存储对象引用,不阻止垃圾回收。
// WeakSet - 只能存放对象,且都是弱引用
const weakSet = new WeakSet();
let obj = { name: "John" };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null; // 对象可以被垃圾回收
// WeakMap - 键必须是对象,且都是弱引用
const weakMap = new WeakMap();
let key = { id: 1 };
weakMap.set(key, "value");
console.log(weakMap.get(key)); // value
key = null; // 对象可以被垃圾回收
7.5 代理与反射
Proxy
Proxy用于创建一个对象的代理,从而可以拦截和修改对象的基本操作。
const target = {
name: "John",
age: 30,
};
const handler = {
get(target, prop, receiver) {
console.log(`Getting ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`Setting ${prop} to ${value}`);
return Reflect.set(target, prop, value, receiver);
},
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Getting name / John
proxy.age = 31; // Setting age to 31
Reflect
Reflect是ES6新增的内置对象,提供了一些与Proxy拦截器方法对应的默认实现。
const obj = { name: "John" };
// 与Object方法对应,但更简洁
console.log(Reflect.has(obj, "name")); // true
console.log(Reflect.get(obj, "name")); // John
Reflect.set(obj, "age", 30);
console.log(Reflect.ownKeys(obj)); // ["name", "age"]
// Reflect.apply: 调用函数并绑定this和参数
function greet(greeting, punctuation) {
return greeting + ", " + this.name + punctuation;
}
const person = { name: "Alice" };
console.log(Reflect.apply(greet, person, ["Hello", "!"])); // Hello, Alice!
// Reflect.construct: 相当于new操作符
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const instance = Reflect.construct(Person, ["Bob", 25]);
console.log(instance.name); // Bob
console.log(instance.age); // 25
// Reflect.getPrototypeOf: 获取原型对象
console.log(Reflect.getPrototypeOf(instance)); // Person.prototype
// Reflect.setPrototypeOf/setPrototypeOf: 设置原型对象
const proto = {
greet() {
return "Hi";
},
};
Reflect.setPrototypeOf(instance, proto);
console.log(Reflect.getPrototypeOf(instance) === proto); // true
// Reflect.defineProperty: 定义属性
Reflect.defineProperty(obj, "city", { value: "Beijing", writable: true });
console.log(obj.city); // Beijing
// Reflect.deleteProperty: 删除属性
Reflect.deleteProperty(obj, "age");
console.log(obj.age); // undefined
// Reflect.isExtensible: 检查对象是否可扩展
console.log(Reflect.isExtensible(obj)); // true
// Reflect.preventExtensions: 阻止对象扩展
Reflect.preventExtensions(obj);
console.log(Reflect.isExtensible(obj)); // false
7.6 迭代器和生成器
迭代器
迭代器是一个对象,具有next方法,返回{value, done}形式的结果。
function createIterator(array) {
let index = 0;
return {
next() {
if (index < array.length) {
return { value: array[index++], done: false };
}
return { value: undefined, done: true };
},
};
}
const iterator = createIterator([1, 2, 3]);
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().done); // false
console.log(iterator.next().done); // true
生成器
生成器是一种特殊的迭代器,使用 function 语法。
function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
console.log(gen.next().done); // true
// 使用for...of遍历
for (const value of generator()) {
console.log(value);
}
8. 性能优化
8.1 代码优化
- 使用let/const代替var
- 避免全局变量
- 使用事件委托
- 减少DOM操作
- 使用requestAnimationFrame进行动画
- 避免频繁重排和重绘
8.2 网络优化
- 减少HTTP请求
- 使用CDN
- 启用Gzip压缩
- 使用缓存
- 延迟加载非关键资源
8.3 工具链
- 使用Babel转译ES6+
- 使用Webpack等构建工具
- 使用ESLint进行代码检查
- 使用Prettier进行代码格式化
9. 最佳实践
9.1 代码质量
- 代码可读性:使用清晰的命名和注释
- 错误处理:使用try/catch和Promise.catch
- 安全性:防止XSS和CSRF攻击
- 可维护性:遵循编码规范和设计模式
- 性能:优化代码和网络请求
9.2 学习建议
通过以上知识点的学习和实践,你将能够掌握JavaScript的核心概念和现代特性,编写出高质量的JavaScript代码。
10. 数组高级方法
10.1 数组迭代方法
const numbers = [1, 2, 3, 4, 5];
// map: 转换数组元素
const doubled = numbers.map(num => num * 2); // [2, 4, 6, 8, 10]
// filter: 过滤数组元素
const evens = numbers.filter(num => num % 2 === 0); // [2, 4]
// reduce: 累加数组元素
const sum = numbers.reduce((acc, num) => acc + num, 0); // 15
// find: 查找第一个符合条件的元素
const found = numbers.find(num => num > 3); // 4
// some: 检查是否有元素满足条件
const hasEven = numbers.some(num => num % 2 === 0); // true
// every: 检查是否所有元素都满足条件
const allPositive = numbers.every(num => num > 0); // true
// forEach: 遍历数组
numbers.forEach(num => console.log(num));
10.2 数组操作方法
const arr = [1, 2, 3, 4, 5];
// flat: 扁平化嵌套数组
const nested = [1, [2, [3, [4, 5]]]];
const flattened = nested.flat(Infinity); // [1, 2, 3, 4, 5]
// flatMap: 映射并扁平化
const doubledFlat = [1, 2, 3].flatMap(num => [num, num * 2]); // [1, 2, 2, 4, 3, 6]
// includes: 检查是否包含元素
const hasValue = arr.includes(3); // true
// sort: 排序
const sorted = arr.sort((a, b) => a - b); // 升序
const sortedDesc = arr.sort((a, b) => b - a); // 降序
// slice: 提取子数组
const sliced = arr.slice(1, 3); // [2, 3]
// splice: 删除或插入元素
// splice(开始位置, 删除数量, 插入元素...)
const arr2 = [1, 2, 3, 4, 5];
arr2.splice(2, 1, 99); // 从索引2开始删除1个元素,插入99
console.log(arr2); // [1, 2, 99, 4, 5]
// concat: 连接数组
const concatenated = arr.concat([6, 7]); // [1, 2, 3, 4, 5, 6, 7]
// reverse: 反转数组(会修改原数组)
const original = [1, 2, 3, 4, 5];
const reversed = [...original].reverse(); // 使用展开运算符创建副本避免修改原数组
console.log(original); // [1, 2, 3, 4, 5] 原数组不变
console.log(reversed); // [5, 4, 3, 2, 1]
10.3 数组解构和展开
// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 数组拷贝
const copy = [...arr1]; // 浅拷贝
11. 正则表达式详细内容
11.1 正则表达式语法
// 基本语法
const pattern = /abc/; // 匹配 "abc"
const patternWithFlags = /abc/gi; // 全局匹配,不区分大小写
// 字符类
const digitPattern = /\d/; // 匹配数字
const letterPattern = /[a-zA-Z]/; // 匹配字母
const notDigitPattern = /\D/; // 匹配非数字
const whitespacePattern = /\s/; // 匹配空白字符
// 量词
const oneOrMore = /a+/; // 一个或多个 a
const zeroOrMore = /a*/; // 零个或多个 a
const zeroOrOne = /a?/; // 零个或一个 a
const exactlyN = /a{3}/; // 恰好3个 a
const atLeastN = /a{3,}/; // 至少3个 a
const rangeN = /a{3,5}/; // 3到5个 a
11.2 正则表达式标志
// g: 全局匹配
const globalPattern = /a/g;
"aaabbb".replace(globalPattern, "x"); // "xxxbbb"
// i: 不区分大小写
const caseInsensitive = /hello/i;
caseInsensitive.test("HELLO"); // true
// m: 多行模式
const multiline = /^hello/m;
multiline.test("first line\nhello"); // true
// u: Unicode模式,用于处理Unicode字符
const unicode = /\u{1F600}/u; // 匹配Unicode字符 😊
// y: 粘滞模式,从lastIndex位置开始匹配
const sticky = /hello/y;
sticky.lastIndex = 3;
console.log(sticky.test("hello hello")); // true
11.3 正则表达式应用
// 验证邮箱
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
emailPattern.test("test@example.com"); // true
// 验证手机号
const phonePattern = /^1[3-9]\d{9}$/;
phonePattern.test("13800138000"); // true
// 提取URL中的域名
const urlPattern = /https?:\/\/([^\/]+)/;
const url = "https://www.example.com/path";
const domain = url.match(urlPattern)[1]; // "www.example.com"
// 替换HTML标签
const html = "<div>Hello</div>";
const text = html.replace(/<[^>]*>/g, ""); // "Hello"
// 分割字符串
const csv = "apple,banana,cherry";
const fruits = csv.split(/,/); // ["apple", "banana", "cherry"]
12. 日期和时间处理
12.1 Date对象基础
// 创建日期对象
const now = new Date(); // 当前时间
const specificDate = new Date(2024, 0, 1); // 2024年1月1日
const fromString = new Date("2024-01-01"); // 从字符串创建
const fromTimestamp = new Date(1704067200000); // 从时间戳创建
// 获取日期部分
const year = now.getFullYear(); // 年份
const month = now.getMonth(); // 月份 (0-11)
const date = now.getDate(); // 日期
const day = now.getDay(); // 星期 (0-6)
const hours = now.getHours(); // 小时
const minutes = now.getMinutes(); // 分钟
const seconds = now.getSeconds(); // 秒
const milliseconds = now.getMilliseconds(); // 毫秒
// 设置日期部分
now.setFullYear(2025);
now.setMonth(0);
now.setDate(1);
12.2 日期格式化和解析
// 格式化日期
const date = new Date();
const formatted = date.toLocaleDateString(); // 本地日期格式
const timeFormatted = date.toLocaleTimeString(); // 本地时间格式
const dateTimeFormatted = date.toLocaleString(); // 本地日期时间格式
// 自定义格式化
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
// 解析日期字符串
const parsedDate = new Date("2024-01-01T00:00:00");
// 时间戳操作
const timestamp = Date.now(); // 当前时间戳
const dateFromTimestamp = new Date(timestamp);
12.3 日期计算和比较
// 日期计算
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const nextWeek = new Date(today);
nextWeek.setDate(today.getDate() + 7);
// 日期比较
const date1 = new Date("2024-01-01");
const date2 = new Date("2024-01-02");
const diff = date2 - date1; // 毫秒差
const daysDiff = diff / (1000 * 60 * 60 * 24); // 天数差
// 判断日期先后
if (date1 < date2) {
console.log("date1 在 date2 之前");
}
13. Math对象和数学运算
13.1 Math对象常用方法
// 基本数学运算
Math.abs(-5); // 5: 绝对值
Math.round(4.7); // 5: 四舍五入
Math.floor(4.9); // 4: 向下取整
Math.ceil(4.1); // 5: 向上取整
Math.trunc(4.9); // 4: 去除小数部分
// 幂运算和对数
Math.pow(2, 3); // 8: 2的3次方
Math.sqrt(16); // 4: 平方根
Math.cbrt(27); // 3: 立方根
Math.log(10); // 自然对数
Math.log10(100); // 以10为底的对数
// 三角函数
Math.sin(Math.PI / 2); // 1
Math.cos(0); // 1
Math.tan(Math.PI / 4); // 1
// 常量
Math.PI; // 3.141592653589793
Math.E; // 2.718281828459045
Math.SQRT2; // 1.4142135623730951
13.2 随机数生成
// 生成0-1之间的随机数
const random = Math.random();
// 生成指定范围的随机整数
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
getRandomInt(1, 10); // 1-10之间的随机整数
// 生成随机字符串
function generateRandomString(length) {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
generateRandomString(10); // 10位随机字符串
13.3 实际应用场景
// 计算两点之间的距离
function getDistance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
}
// 限制数值范围
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
clamp(15, 0, 10); // 10
clamp(5, 0, 10); // 5
clamp(-5, 0, 10); // 0
// 线性插值
function lerp(start, end, t) {
return start + (end - start) * t;
}
lerp(0, 10, 0.5); // 5
14. 类型转换和类型检查
14.1 显式类型转换
// 转换为字符串
String(123); // "123"
String(true); // "true"
String(null); // "null"
(123).toString(); // "123"
true.toString(); // "true"
// 转换为数字
Number("123"); // 123
Number("123abc"); // NaN
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN
parseInt("123"); // 123
parseInt("123abc"); // 123
parseFloat("123.45"); // 123.45
// 转换为布尔值
Boolean(1); // true
Boolean(0); // false
Boolean("hello"); // true
Boolean(""); // false
Boolean(null); // false
Boolean(undefined); // false
14.2 隐式类型转换
// 字符串拼接
"5" + 5; // "55"
"5" + true; // "5true"
// 算术运算
"5" - 3; // 2
"5" * 2; // 10
"5" / 2; // 2.5
// 比较运算
5 == "5"; // true (类型转换)
5 === "5"; // false (严格相等)
// 逻辑运算
!0; // true
!!0; // false
!"hello"; // false
14.3 精确类型检查
// 基本类型检查
typeof "hello"; // "string"
typeof 123; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof null; // "object" (历史遗留问题)
typeof {}; // "object"
typeof []; // "object"
typeof function () {}; // "function"
// 数组检查
Array.isArray([1, 2, 3]); // true
Array.isArray({}); // false
// NaN检查
Number.isNaN(NaN); // true
Number.isNaN(123); // false
isNaN(NaN); // true
isNaN("hello"); // true (会先转换为数字)
// 有限数检查
Number.isFinite(123); // true
Number.isFinite(Infinity); // false
Number.isFinite(NaN); // false
// 整数检查
Number.isInteger(123); // true
Number.isInteger(123.45); // false
Number.isInteger("123"); // false
// 安全整数检查
Number.isSafeInteger(9007199254740991); // true
Number.isSafeInteger(9007199254740992); // false
15. 闭包和作用域链
15.1 作用域和作用域链
// 全局作用域
var globalVar = "全局变量";
function outerFunction() {
// 外部函数作用域
var outerVar = "外部变量";
function innerFunction() {
// 内部函数作用域
var innerVar = "内部变量";
console.log(innerVar); // 可以访问
console.log(outerVar); // 可以访问
console.log(globalVar); // 可以访问
}
innerFunction();
// console.log(innerVar); // 错误:无法访问
}
outerFunction();
// console.log(outerVar); // 错误:无法访问
15.2 闭包的概念
// 闭包:函数能够记住并访问其词法作用域
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2
console.log(counter2()); // 1 (独立的闭包)
console.log(counter1()); // 3
15.3 闭包的实际应用
// 数据私有化
function createPerson(name) {
let _name = name;
return {
getName: function () {
return _name;
},
setName: function (newName) {
_name = newName;
},
};
}
const person = createPerson("John");
console.log(person.getName()); // "John"
person.setName("Jane");
console.log(person.getName()); // "Jane"
// 函数工厂
function createMultiplier(multiplier) {
return function (x) {
return x * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// 事件处理
function setupButtons() {
for (let i = 0; i < 3; i++) {
document.getElementById(`btn${i}`).onclick = function () {
console.log(`Button ${i} clicked`);
};
}
}
15.4 内存泄漏和性能
// 避免内存泄漏
function setupEventHandlers() {
const elements = document.querySelectorAll(".item");
elements.forEach(element => {
element.addEventListener("click", function handler() {
console.log("Clicked");
// 使用完后移除事件监听器
element.removeEventListener("click", handler);
});
});
}
// 及时释放闭包引用
function createClosure() {
const largeData = new Array(1000000).fill("data");
return function () {
// 使用largeData
console.log(largeData.length);
};
}
const closure = createClosure();
closure();
// 使用完后将引用设为null
closure = null;
16. 设计模式在JavaScript中的应用
16.1 单例模式
// 单例模式:确保一个类只有一个实例
const Singleton = (function () {
let instance;
function createInstance() {
return {
data: [],
add: function (item) {
this.data.push(item);
},
get: function () {
return this.data;
},
};
}
return {
getInstance: function () {
if (!instance) {
instance = createInstance();
}
return instance;
},
};
})();
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
16.2 工厂模式
// 工厂模式:创建对象的接口
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
drive() {
console.log(`Driving ${this.make} ${this.model}`);
}
}
class CarFactory {
static createCar(type) {
switch (type) {
case "sedan":
return new Car("Toyota", "Camry");
case "suv":
return new Car("Honda", "CR-V");
case "sports":
return new Car("Porsche", "911");
default:
throw new Error("Unknown car type");
}
}
}
const sedan = CarFactory.createCar("sedan");
const suv = CarFactory.createCar("suv");
16.3 观察者模式
// 观察者模式:对象间的一对多依赖关系
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify("Hello Observers!");
16.4 模块模式
// 模块模式:封装私有变量和方法
const Module = (function () {
let privateVar = 0;
function privateFunction() {
console.log("Private function");
}
return {
publicMethod: function () {
privateVar++;
privateFunction();
return privateVar;
},
publicVar: 42,
};
})();
console.log(Module.publicVar); // 42
console.log(Module.publicMethod()); // 1
// Module.privateVar; // undefined
// Module.privateFunction(); // undefined
16.5 策略模式
// 策略模式:定义算法族,分别封装
const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
divide: (a, b) => a / b,
};
function calculate(strategy, a, b) {
if (!strategies[strategy]) {
throw new Error("Unknown strategy");
}
return strategies[strategy](a, b);
}
console.log(calculate("add", 5, 3)); // 8
console.log(calculate("multiply", 5, 3)); // 15
17. 函数式编程
17.1 高阶函数
// 高阶函数:接收函数作为参数或返回函数
function withLogging(fn) {
return function (...args) {
console.log(`Calling ${fn.name} with`, args);
const result = fn(...args);
console.log(`Result:`, result);
return result;
};
}
const add = (a, b) => a + b;
const loggedAdd = withLogging(add);
loggedAdd(5, 3); // 输出日志并返回8
17.2 纯函数和副作用
// 纯函数:相同输入总是产生相同输出,无副作用
const pureAdd = (a, b) => a + b;
console.log(pureAdd(2, 3)); // 5
console.log(pureAdd(2, 3)); // 5
// 非纯函数:有副作用
let counter = 0;
const impureAdd = (a, b) => {
counter++;
return a + b;
};
// 避免副作用
const pureAddWithCounter = (a, b, count) => ({
result: a + b,
newCount: count + 1,
});
17.3 函数组合
// 函数组合:将多个函数组合成一个
const compose =
(...fns) =>
x =>
fns.reduceRight((v, f) => f(v), x);
const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;
const composed = compose(square, double, addOne);
console.log(composed(3)); // square(double(3 + 1)) = square(8) = 64
// 管道:从左到右组合
const pipe =
(...fns) =>
x =>
fns.reduce((v, f) => f(v), x);
const piped = pipe(addOne, double, square);
console.log(piped(3)); // square(double(3 + 1)) = 64
17.4 柯里化和偏函数
// 柯里化:将多参数函数转换为单参数函数链
const curry = fn => {
const curried = (...args) => {
if (args.length >= fn.length) {
return fn(...args);
}
return (...more) => curried(...args, ...more);
};
return curried;
};
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
// 偏函数:预设部分参数
const partial =
(fn, ...presetArgs) =>
(...laterArgs) =>
fn(...presetArgs, ...laterArgs);
const multiply = (a, b, c) => a * b * c;
const doubleAndTriple = partial(multiply, 2, 3);
console.log(doubleAndTriple(4)); // 24
18. TypeScript基础
18.1 类型系统
// 基本类型
let name: string = "John";
let age: number = 30;
let isStudent: boolean = true;
let nothing: null = null;
let notDefined: undefined = undefined;
// 数组类型
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];
// 对象类型
interface Person {
name: string;
age: number;
}
let person: Person = {
name: "John",
age: 30,
};
// 联合类型
let value: string | number = "hello";
value = 42;
// 字面量类型
let direction: "up" | "down" | "left" | "right" = "up";
18.2 接口和类型别名
// 接口
interface User {
id: number;
name: string;
email?: string; // 可选属性
readonly createdAt: Date; // 只读属性
}
const user: User = {
id: 1,
name: "John",
createdAt: new Date(),
};
// 类型别名
type ID = number | string;
type Coordinates = {
x: number;
y: number;
};
let userId: ID = 123;
let position: Coordinates = { x: 10, y: 20 };
18.3 泛型
// 泛型函数
function identity<T>(arg: T): T {
return arg;
}
identity<string>("hello");
identity<number>(42);
// 泛型接口
interface Box<T> {
value: T;
}
const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 42 };
// 泛型约束
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("hello"); // 5
logLength([1, 2, 3]); // 3
18.4 类和装饰器
// 类
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
speak(): void {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
speak(): void {
console.log(`${this.name} barks`);
}
}
const dog = new Dog("Buddy", "Golden Retriever");
dog.speak();
// 装饰器
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
19. 前端测试
19.1 单元测试基础
// Jest测试示例
describe("Math operations", () => {
test("add two numbers", () => {
expect(add(2, 3)).toBe(5);
});
test("subtract two numbers", () => {
expect(subtract(5, 3)).toBe(2);
});
test("async operation", async () => {
const result = await fetchData();
expect(result).toBe("data");
});
});
// 测试函数
function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
async function fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve("data"), 100);
});
}
19.2 测试覆盖率
// 配置Jest覆盖率
module.exports = {
collectCoverage: true,
coverageDirectory: "coverage",
collectCoverageFrom: ["src/**/*.{js,jsx}", "!src/**/*.test.{js,jsx}", "!src/**/*.d.ts"],
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};
19.3 测试最佳实践
// AAA模式:Arrange, Act, Assert
describe("User service", () => {
test("create user successfully", () => {
// Arrange: 准备测试数据
const userData = {
name: "John",
email: "john@example.com",
};
// Act: 执行被测试的代码
const user = userService.create(userData);
// Assert: 验证结果
expect(user.name).toBe("John");
expect(user.email).toBe("john@example.com");
expect(user.id).toBeDefined();
});
});
// Mock外部依赖
jest.mock("./api");
import { fetchUser } from "./api";
test("fetch user data", async () => {
fetchUser.mockResolvedValue({ name: "John" });
const data = await getUserData(1);
expect(data.name).toBe("John");
expect(fetchUser).toHaveBeenCalledWith(1);
});
20. Web API扩展
20.1 Canvas API
// 基本绘图
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 绘制矩形
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 100, 100);
// 绘制圆形
ctx.beginPath();
ctx.arc(150, 150, 50, 0, Math.PI * 2);
ctx.fillStyle = "blue";
ctx.fill();
// 绘制线条
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(200, 200);
ctx.strokeStyle = "green";
ctx.stroke();
// 绘制文本
ctx.font = "20px Arial";
ctx.fillStyle = "black";
ctx.fillText("Hello Canvas", 10, 50);
20.2 WebGL基础
// 初始化WebGL
const canvas = document.getElementById("webglCanvas");
const gl = canvas.getContext("webgl");
// 顶点着色器
const vsSource = `
attribute vec4 aVertexPosition;
void main() {
gl_Position = aVertexPosition;
}
`;
// 片段着色器
const fsSource = `
void main() {
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
`;
// 编译着色器
function loadShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
}
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
// 创建程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
20.3 WebRTC
// 获取媒体流
async function startVideo() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
const videoElement = document.getElementById("localVideo");
videoElement.srcObject = stream;
videoElement.play();
} catch (error) {
console.error("Error accessing media devices:", error);
}
}
// WebRTC连接
const peerConnection = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
});
peerConnection.onicecandidate = event => {
if (event.candidate) {
// 发送ICE候选到对方
sendCandidate(event.candidate);
}
};
peerConnection.ontrack = event => {
const remoteVideo = document.getElementById("remoteVideo");
remoteVideo.srcObject = event.streams[0];
};
20.4 Notification API
// 请求通知权限
function requestNotificationPermission() {
Notification.requestPermission().then(permission => {
if (permission === "granted") {
showNotification();
}
});
}
// 显示通知
function showNotification() {
const notification = new Notification("Hello!", {
body: "This is a notification",
icon: "/icon.png",
tag: "unique-tag",
});
notification.onclick = () => {
window.focus();
notification.close();
};
}
// 检查权限
if (Notification.permission === "default") {
requestNotificationPermission();
}
21. 安全性深入
21.1 XSS攻击防护
// 输入转义
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// 使用textContent而不是innerHTML
const userContent = escapeHtml(userInput);
element.textContent = userContent;
// CSP (Content Security Policy)
// 在HTTP头中设置
// Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com
21.2 CSRF攻击防护
// CSRF Token
function getCsrfToken() {
return document.querySelector('meta[name="csrf-token"]').getAttribute("content");
}
// 在请求中包含CSRF Token
fetch("/api/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": getCsrfToken(),
},
body: JSON.stringify({ data: "value" }),
});
// SameSite Cookie属性
// Set-Cookie: sessionId=abc123; SameSite=Strict; Secure
21.3 数据加密和哈希
// 使用Web Crypto API进行哈希
async function hashPassword(password) {
const encoder = new TextEncoder();
const data = encoder.encode(password);
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
return hashHex;
}
// 生成随机值
function generateRandomBytes(length) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return Array.from(array)
.map(b => b.toString(16).padStart(2, "0"))
.join("");
}
// 使用示例
hashPassword("mypassword").then(hash => {
console.log("Password hash:", hash);
});
22. 性能监控和分析
22.1 Performance API
// 测量页面加载时间
window.addEventListener("load", () => {
const perfData = performance.getEntriesByType("navigation")[0];
console.log("页面加载时间:", perfData.loadEventEnd - perfData.fetchStart);
console.log("DNS查询时间:", perfData.domainLookupEnd - perfData.domainLookupStart);
console.log("TCP连接时间:", perfData.connectEnd - perfData.connectStart);
console.log("请求响应时间:", perfData.responseEnd - perfData.requestStart);
});
// 测量特定操作
const startMark = "operation-start";
const endMark = "operation-end";
performance.mark(startMark);
// 执行需要测量的操作
performExpensiveOperation();
performance.mark(endMark);
performance.measure("operation", startMark, endMark);
const measure = performance.getEntriesByName("operation")[0];
console.log("操作耗时:", measure.duration, "ms");
22.2 内存分析
// 获取内存使用情况
function getMemoryUsage() {
if (performance.memory) {
return {
usedJSHeapSize: performance.memory.usedJSHeapSize,
totalJSHeapSize: performance.memory.totalJSHeapSize,
jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
};
}
return null;
}
// 监控内存泄漏
let memorySnapshots = [];
function takeMemorySnapshot() {
const memory = getMemoryUsage();
if (memory) {
memorySnapshots.push({
timestamp: Date.now(),
...memory,
});
if (memorySnapshots.length > 10) {
memorySnapshots.shift();
}
checkMemoryLeak();
}
}
function checkMemoryLeak() {
if (memorySnapshots.length < 2) return;
const first = memorySnapshots[0];
const last = memorySnapshots[memorySnapshots.length - 1];
const growth = last.usedJSHeapSize - first.usedJSHeapSize;
if (growth > 1000000) {
// 超过1MB增长
console.warn("可能的内存泄漏:", growth, "bytes");
}
}
22.3 网络性能监控
// 监控资源加载
const resourceObserver = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.log("资源加载:", entry.name);
console.log("加载时间:", entry.duration, "ms");
console.log("大小:", entry.transferSize, "bytes");
}
});
resourceObserver.observe({ entryTypes: ["resource"] });
// 监控长任务
const longTaskObserver = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.warn("长任务检测到:", entry.duration, "ms");
console.log("开始时间:", entry.startTime);
}
});
longTaskObserver.observe({ entryTypes: ["longtask"] });
23. 代码组织和架构
23.1 MVC模式
// Model: 数据模型
class UserModel {
constructor(data) {
this.data = data;
}
get name() {
return this.data.name;
}
set name(value) {
this.data.name = value;
}
}
// View: 视图
class UserView {
constructor(element) {
this.element = element;
}
render(user) {
this.element.innerHTML = `
<h1>${user.name}</h1>
<p>Email: ${user.email}</p>
`;
}
}
// Controller: 控制器
class UserController {
constructor(model, view) {
this.model = model;
this.view = view;
}
handleNameChange(newName) {
this.model.name = newName;
this.view.render(this.model);
}
}
// 使用
const model = new UserModel({ name: "John", email: "john@example.com" });
const view = new UserView(document.getElementById("app"));
const controller = new UserController(model, view);
view.render(model);
23.2 状态管理
// 简单的状态管理器
class Store {
constructor(initialState) {
this.state = initialState;
this.listeners = [];
}
getState() {
return this.state;
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.notify();
}
subscribe(listener) {
this.listeners.push(listener);
return () => {
this.listeners = this.listeners.filter(l => l !== listener);
};
}
notify() {
this.listeners.forEach(listener => listener(this.state));
}
}
// 使用
const store = new Store({ count: 0, name: "John" });
store.subscribe(state => {
console.log("State changed:", state);
});
store.setState({ count: 1 });
store.setState({ name: "Jane" });
23.3 依赖注入
// 服务类
class Logger {
log(message) {
console.log(`[LOG] ${message}`);
}
}
class Database {
constructor(logger) {
this.logger = logger;
}
query(sql) {
this.logger.log(`Executing query: ${sql}`);
// 执行数据库查询
}
}
class UserService {
constructor(database, logger) {
this.database = database;
this.logger = logger;
}
getUser(id) {
this.logger.log(`Getting user ${id}`);
return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
// 依赖注入容器
class Container {
constructor() {
this.services = new Map();
}
register(name, factory) {
this.services.set(name, factory);
}
get(name) {
const factory = this.services.get(name);
if (!factory) {
throw new Error(`Service ${name} not found`);
}
return factory(this);
}
}
// 使用
const container = new Container();
container.register("logger", () => new Logger());
container.register("database", c => new Database(c.get("logger")));
container.register("userService", c => new UserService(c.get("database"), c.get("logger")));
const userService = container.get("userService");
userService.getUser(1);
24. 浏览器兼容性处理
24.1 Polyfill使用
// 检测特性支持
function supportsFeature(feature) {
return feature in window || feature in document;
}
// Array.prototype.includes polyfill
if (!Array.prototype.includes) {
Array.prototype.includes = function (searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
const O = Object(this);
const len = O.length >>> 0;
let k = fromIndex || 0;
if (k < 0) {
k = Math.max(0, len + k);
}
for (; k < len; k++) {
if (O[k] === searchElement) {
return true;
}
}
return false;
};
}
// Fetch API polyfill
if (!window.fetch) {
window.fetch = function (url, options) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(options?.method || "GET", url);
xhr.onload = () =>
resolve({
ok: xhr.status >= 200 && xhr.status < 300,
status: xhr.status,
text: () => xhr.responseText,
});
xhr.onerror = () => reject(new Error("Network error"));
xhr.send(options?.body);
});
};
}
24.2 Babel配置
// babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
browsers: ["> 1%", "last 2 versions", "not ie <= 11"],
},
useBuiltIns: "usage",
corejs: 3,
},
],
],
plugins: [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
],
};
24.3 特性检测和优雅降级
// 特性检测
const features = {
flexbox: CSS.supports("display", "flex"),
grid: CSS.supports("display", "grid"),
webp: document.createElement("canvas").toDataURL("image/webp").indexOf("data:image/webp") === 0,
touch: "ontouchstart" in window,
};
// 优雅降级
function applyLayout() {
if (features.grid) {
container.style.display = "grid";
} else if (features.flexbox) {
container.style.display = "flex";
} else {
container.style.display = "block";
}
}
// 渐进增强
function enhanceWithWebP() {
if (features.webp) {
const images = document.querySelectorAll("img[data-webp]");
images.forEach(img => {
img.src = img.dataset.webp;
});
}
}
25. 响应式设计和移动端
25.1 媒体查询
// 检测视口大小
function getViewportSize() {
return {
width: window.innerWidth,
height: window.innerHeight,
};
}
// 监听视口变化
function setupResponsiveHandlers() {
const handlers = {
mobile: () => console.log("Mobile view"),
tablet: () => console.log("Tablet view"),
desktop: () => console.log("Desktop view"),
};
function checkViewport() {
const width = window.innerWidth;
if (width < 768) {
handlers.mobile();
} else if (width < 1024) {
handlers.tablet();
} else {
handlers.desktop();
}
}
window.addEventListener("resize", checkViewport);
checkViewport();
}
25.2 触摸事件
// 触摸事件处理
function setupTouchHandlers() {
const element = document.getElementById("touchElement");
element.addEventListener("touchstart", e => {
console.log("Touch start:", e.touches[0].clientX, e.touches[0].clientY);
});
element.addEventListener("touchmove", e => {
e.preventDefault(); // 防止滚动
console.log("Touch move:", e.touches[0].clientX, e.touches[0].clientY);
});
element.addEventListener("touchend", e => {
console.log("Touch end");
});
// 手势识别
let startX, startY;
element.addEventListener("touchstart", e => {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
});
element.addEventListener("touchend", e => {
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const diffX = endX - startX;
const diffY = endY - startY;
if (Math.abs(diffX) > Math.abs(diffY)) {
if (diffX > 50) {
console.log("Swipe right");
} else if (diffX < -50) {
console.log("Swipe left");
}
} else {
if (diffY > 50) {
console.log("Swipe down");
} else if (diffY < -50) {
console.log("Swipe up");
}
}
});
}
25.3 设备API
// 电池状态API
if ("getBattery" in navigator) {
navigator.getBattery().then(battery => {
function updateBatteryStatus() {
console.log("Battery level:", battery.level * 100, "%");
console.log("Charging:", battery.charging);
if (battery.charging) {
console.log("Time to full:", battery.chargingTime, "seconds");
} else {
console.log("Time to empty:", battery.dischargingTime, "seconds");
}
}
updateBatteryStatus();
battery.addEventListener("levelchange", updateBatteryStatus);
battery.addEventListener("chargingchange", updateBatteryStatus);
});
}
// 震动API
function vibrate(pattern) {
if ("vibrate" in navigator) {
navigator.vibrate(pattern);
}
}
vibrate([200, 100, 200]); // 震动200ms,暂停100ms,再震动200ms
// 屏幕方向API
window.addEventListener("orientationchange", () => {
console.log("Orientation changed:", screen.orientation.angle);
});
// PWA基础
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js").then(registration => {
console.log("Service Worker registered");
});
}
26. 构建工具深入
26.1 Webpack高级配置
// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
main: "./src/index.js",
vendor: "./src/vendor.js",
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[contenthash].js",
chunkFilename: "[name].[contenthash].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
},
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "images/",
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
}),
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
}),
],
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "all",
},
},
},
},
};
26.2 Vite使用
// vite.config.js
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
build: {
outDir: "dist",
assetsDir: "assets",
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ["react", "react-dom"],
utils: ["lodash", "axios"],
},
},
},
},
server: {
port: 3000,
proxy: {
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ""),
},
},
},
});
26.3 代码优化和压缩
// Terser配置(代码压缩)
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
pure_funcs: ["console.log"],
},
mangle: {
safari10: true,
},
},
extractComments: false,
}),
],
},
};
// 图片优化
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
type: "asset",
use: [
{
loader: ImageMinimizerPlugin.loader,
options: {
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["imagemin-mozjpeg", { quality: 80 }],
["imagemin-pngquant", { quality: [0.65, 0.9] }],
],
},
},
},
},
],
},
],
},
};
27. 调试技巧
27.1 Chrome DevTools高级用法
// Console高级用法
console.log("Basic log");
console.info("Info message");
console.warn("Warning message");
console.error("Error message");
console.table([
{ name: "John", age: 30 },
{ name: "Jane", age: 25 },
]);
console.group("User Data");
console.log("Name: John");
console.log("Age: 30");
console.groupEnd();
console.time("Operation");
performOperation();
console.timeEnd("Operation");
console.assert(1 === 2, "This will fail");
// 条件断点
// 在代码中添加 debugger; 语句
function debugFunction() {
const x = 5;
debugger; // 程序会在这里暂停
const y = x + 10;
return y;
}
// 性能分析
console.profile("MyProfile");
// 执行需要分析的代码
console.profileEnd("MyProfile");
// 内存快照
console.memory; // 查看内存使用情况
27.2 断点调试
// 条件断点
function processArray(arr) {
for (let i = 0; i < arr.length; i++) {
// 当 i === 5 时触发断点
if (i === 5) {
debugger;
}
console.log(arr[i]);
}
}
// 日志断点
function complexCalculation(a, b) {
const result = a * b + Math.sqrt(a);
// 在控制台输出调试信息
console.log(`Calculation: ${a} * ${b} + sqrt(${a}) = ${result}`);
return result;
}
// 监控变量
function monitorVariable(obj, prop) {
let value = obj[prop];
Object.defineProperty(obj, prop, {
get() {
console.log(`Getting ${prop}:`, value);
return value;
},
set(newValue) {
console.log(`Setting ${prop}:`, value, "->", newValue);
value = newValue;
},
});
}
const user = { name: "John", age: 30 };
monitorVariable(user, "name");
user.name = "Jane"; // 控制台会输出设置信息
console.log(user.name); // 控制台会输出获取信息
27.3 网络调试
// 监控网络请求
const originalFetch = window.fetch;
window.fetch = function (...args) {
console.log("Fetch request:", args[0]);
return originalFetch.apply(this, args).then(response => {
console.log("Fetch response:", response.status, response.url);
return response;
});
};
// 监控XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url) {
this._method = method;
this._url = url;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function () {
console.log("XHR request:", this._method, this._url);
this.addEventListener("load", () => {
console.log("XHR response:", this.status, this._url);
});
return originalSend.apply(this, arguments);
};
通过以上27个章节的全面学习,你将能够掌握JavaScript从基础到高级的所有核心概念和现代特性,编写出高质量、高性能、安全的JavaScript代码。