全局变量
所有代码都在全局作用域,容易产生命名冲突
var myFunction = function() { };
现代JavaScript(ES6+)带来了许多强大的新特性。通过学习这些进阶技术, 你将能够编写更加优雅、高效和可维护的JavaScript代码。
Brendan Eich在Netscape创造了JavaScript
引入严格模式、JSON支持等特性
let/const、箭头函数、类、模块化
持续演进,每年发布新特性
ES6+引入了许多新的语法特性,让JavaScript编程更加简洁和强大。
特性 | var | let | const |
---|---|---|---|
作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
变量提升 | 有 | 无 | 无 |
重复声明 | 允许 | 不允许 | 不允许 |
重新赋值 | 允许 | 允许 | 不允许 |
function scopeTest() { if (true) { var varVariable = "我是var"; let letVariable = "我是let"; const constVariable = "我是const"; } console.log(varVariable); // 可以访问 try { console.log(letVariable); // 报错 } catch (e) { console.log("let变量作用域错误:", e.message); } try { console.log(constVariable); // 报错 } catch (e) { console.log("const变量作用域错误:", e.message); } } scopeTest();
点击"运行代码"查看结果
console.log("=== 变量提升演示 ==="); // var 变量提升 console.log("var变量:", varTest); // undefined (已提升但未赋值) var varTest = "var已赋值"; console.log("var变量:", varTest); // "var已赋值" // let 和 const 不会提升 try { console.log("let变量:", letTest); // 报错 } catch (e) { console.log("let访问错误:", e.message); } let letTest = "let已赋值"; console.log("let变量:", letTest); // const 同样不会提升 try { console.log("const变量:", constTest); // 报错 } catch (e) { console.log("const访问错误:", e.message); } const constTest = "const已赋值"; console.log("const变量:", constTest);
点击"运行代码"查看结果
console.log("=== 循环中的var vs let ==="); // 使用var的问题 console.log("var版本:"); for (var i = 0; i < 3; i++) { setTimeout(() => { console.log("var i:", i); // 都打印3 }, 100); } // 使用let的解决方案 console.log("let版本:"); for (let j = 0; j < 3; j++) { setTimeout(() => { console.log("let j:", j); // 打印0, 1, 2 }, 200); } // 立即执行函数的var解决方案(ES6之前) console.log("IIFE版本:"); for (var k = 0; k < 3; k++) { (function(index) { setTimeout(() => { console.log("IIFE k:", index); // 打印0, 1, 2 }, 300); })(k); }
点击"运行代码"查看结果
箭头函数提供了更简洁的函数语法,并且没有自己的this绑定。
// 传统函数表达式
const multiply = function(a, b) {
return a * b;
};
// 传统函数声明
function add(a, b) {
return a + b;
}
// 箭头函数
const multiply = (a, b) => a * b;
// 单参数可省略括号
const square = x => x * x;
// 无参数需要空括号
const greet = () => "Hello World";
// 多行需要大括号和return
const complex = (a, b) => {
const result = a * b;
return result + 1;
};
解构赋值允许你从数组和对象中提取值,并赋值给变量。
// 基础数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, , fourth] = numbers;
// first = 1, second = 2, fourth = 4
// 默认值
const [a, b, c = 0] = [1, 2];
// a = 1, b = 2, c = 0
// 交换变量
let x = 1, y = 2;
[x, y] = [y, x];
// x = 2, y = 1
// 剩余参数
const [head, ...tail] = [1, 2, 3, 4];
// head = 1, tail = [2, 3, 4]
// 基础对象解构
const person = { name: '张三', age: 25, city: '北京' };
const { name, age } = person;
// name = '张三', age = 25
// 重命名变量
const { name: personName, age: personAge } = person;
// personName = '张三', personAge = 25
// 默认值
const { name, age, country = '中国' } = person;
// country = '中国'
// 嵌套解构
const user = {
id: 1,
profile: {
name: '李四',
settings: { theme: 'dark' }
}
};
const { profile: { name, settings: { theme } } } = user;
// name = '李四', theme = 'dark'
// 函数参数解构
function greetUser({ name, age = 18 }) {
return `你好 ${name},你今年 ${age} 岁`;
}
// 数组参数解构
function processCoordinates([x, y, z = 0]) {
return { x, y, z };
}
// 混合解构
function createUser({ name, ...otherInfo }, [role, permission]) {
return {
name,
role,
permission,
...otherInfo
};
}
挑战:从以下数据中提取所需信息
const apiResponse = { status: 'success', data: { users: [ { id: 1, name: '张三', email: 'zhangsan@example.com' }, { id: 2, name: '李四', email: 'lisi@example.com' } ], pagination: { page: 1, total: 2 } } };
任务:提取第一个用户的姓名和邮箱,以及总用户数
模板字符串提供了更强大的字符串处理能力,支持多行字符串和表达式插值。
// 字符串拼接
var name = '张三';
var age = 25;
var message = '你好,我是' + name +
',今年' + age + '岁';
// 多行字符串
var html = '<div>' +
' <h1>标题</h1>' +
' <p>内容</p>' +
'</div>';
// 表达式插值
const name = '张三';
const age = 25;
const message = `你好,我是${name},今年${age}岁`;
// 多行字符串
const html = `
<div>
<h1>标题</h1>
<p>内容</p>
</div>`;
// 表达式计算
const total = `总价:${price * quantity}元`;
const message = `你好,我是${name},今年${age}岁,来自${city}`;
标签模板是模板字符串的高级形式,允许你用函数解析模板字符串。
// 高亮函数
function highlight(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? `<mark>${values[i]}</mark>` : '';
return result + string + value;
}, '');
}
const name = '张三';
const score = 95;
const message = highlight`学生 ${name} 的成绩是 ${score} 分`;
// 输出:学生 <mark>张三</mark> 的成绩是 <mark>95</mark> 分
三个点(...)语法在不同上下文中有不同的作用。
// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 对象展开
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
// 函数调用
const numbers = [1, 2, 3, 4, 5];
const max = Math.max(...numbers); // 相当于 Math.max(1, 2, 3, 4, 5)
// 复制数组/对象
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray]; // 浅拷贝
const originalObject = { name: '张三', age: 25 };
const copiedObject = { ...originalObject }; // 浅拷贝
// 函数剩余参数
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
console.log(sum(5, 10)); // 15
// 混合参数
function greet(greeting, ...names) {
return `${greeting} ${names.join(', ')}!`;
}
console.log(greet('Hello', '张三', '李四', '王五'));
// "Hello 张三, 李四, 王五!"
// 数组解构中的剩余参数
const [first, second, ...others] = [1, 2, 3, 4, 5];
// first = 1, second = 2, others = [3, 4, 5]
// 对象解构中的剩余参数
const { name, age, ...otherInfo } = {
name: '张三',
age: 25,
city: '北京',
hobby: '编程'
};
// name = '张三', age = 25, otherInfo = { city: '北京', hobby: '编程' }
// 数组的深度解构
const nestedArray = [[1, 2], [3, 4], [5, 6]];
const [[a, b], [c, d], ...rest] = nestedArray;
// a=1, b=2, c=3, d=4, rest=[[5, 6]]
// 对象的深度解构与重命名
const user = {
name: '张三',
profile: {
age: 25,
address: {
city: '北京',
district: '朝阳区'
}
},
hobbies: ['编程', '阅读', '运动']
};
const {
name: userName,
profile: {
age,
address: { city, district }
},
hobbies: [firstHobby, ...otherHobbies]
} = user;
// 函数参数的复杂解构
function processOrder({
orderId,
customer: { name, email },
items = [],
shipping = { method: 'standard' },
...metadata
}) {
return {
id: orderId,
customerName: name,
customerEmail: email,
itemCount: items.length,
shippingMethod: shipping.method,
additionalInfo: metadata
};
}
使用展开运算符和剩余参数创建实用的工具函数:
const unique = (...arrays) =>
[...new Set(arrays.flat())];
const merge = (...objects) =>
objects.reduce((acc, obj) => ({...acc, ...obj}), {});
const chunk = (array, size) =>
Array.from({length: Math.ceil(array.length / size)},
(_, i) => array.slice(i * size, i * size + size));
const deepClone = (obj) =>
JSON.parse(JSON.stringify(obj));
ES6引入了class语法,提供了更清晰的面向对象编程方式。
// 定义一个基础类
class Person {
// 构造函数
constructor(name, age) {
this.name = name;
this.age = age;
this._id = Math.random().toString(36).substr(2, 9); // 私有属性约定
}
// 实例方法
introduce() {
return `我是${this.name},今年${this.age}岁`;
}
// getter方法
get id() {
return this._id;
}
// setter方法
set age(value) {
if (value > 0 && value < 150) {
this._age = value;
} else {
throw new Error('年龄必须在0-150之间');
}
}
get age() {
return this._age;
}
// 静态方法
static compare(person1, person2) {
return person1.age - person2.age;
}
// 静态属性
static species = 'Homo sapiens';
}
// 使用类
const person1 = new Person('张三', 25);
const person2 = new Person('李四', 30);
console.log(person1.introduce()); // "我是张三,今年25岁"
console.log(Person.compare(person1, person2)); // -5
console.log(Person.species); // "Homo sapiens"
// 父类
class Animal {
constructor(name, species) {
this.name = name;
this.species = species;
}
makeSound() {
return `${this.name}发出了声音`;
}
move() {
return `${this.name}在移动`;
}
}
// 子类继承父类
class Dog extends Animal {
constructor(name, breed) {
super(name, '犬类'); // 调用父类构造函数
this.breed = breed;
}
// 重写父类方法
makeSound() {
return `${this.name}汪汪叫`;
}
// 子类特有方法
wagTail() {
return `${this.name}摇尾巴`;
}
// 调用父类方法
introduce() {
return `${super.makeSound()},它是一只${this.breed}`;
}
}
class Cat extends Animal {
constructor(name, color) {
super(name, '猫科');
this.color = color;
}
makeSound() {
return `${this.name}喵喵叫`;
}
climb() {
return `${this.color}色的${this.name}在爬树`;
}
}
// 使用继承
const dog = new Dog('旺财', '金毛');
const cat = new Cat('咪咪', '橘');
console.log(dog.makeSound()); // "旺财汪汪叫"
console.log(dog.introduce()); // "旺财发出了声音,它是一只金毛"
console.log(cat.climb()); // "橘色的咪咪在爬树"
// 使用私有字段 (ES2022)
class BankAccount {
#balance = 0; // 私有字段
#accountNumber; // 私有字段
constructor(initialBalance, accountNumber) {
this.#balance = initialBalance;
this.#accountNumber = accountNumber;
}
// 公共方法访问私有字段
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return `存入${amount}元,余额:${this.#balance}元`;
}
throw new Error('存款金额必须大于0');
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
return `取出${amount}元,余额:${this.#balance}元`;
}
throw new Error('取款金额无效');
}
get balance() {
return this.#balance;
}
// 私有方法
#validateTransaction(amount) {
return amount > 0 && amount <= this.#balance;
}
// 静态私有字段
static #bankName = '学习银行';
static getBankName() {
return this.#bankName;
}
}
// Mixin模式
const Flyable = {
fly() {
return `${this.name}在飞行`;
}
};
const Swimmable = {
swim() {
return `${this.name}在游泳`;
}
};
class Duck extends Animal {
constructor(name) {
super(name, '鸭类');
}
}
// 添加混入功能
Object.assign(Duck.prototype, Flyable, Swimmable);
const duck = new Duck('唐老鸭');
console.log(duck.fly()); // "唐老鸭在飞行"
console.log(duck.swim()); // "唐老鸭在游泳"
任务:设计一个图书管理系统
JavaScript是单线程语言,异步编程是处理耗时操作的重要技术。
最早的异步解决方案,但容易产生"回调地狱"
getData(callback)
解决回调地狱,提供链式调用
promise.then().catch()
让异步代码看起来像同步代码
await asyncFunction()
// 基础回调函数
function fetchUserData(userId, callback) {
setTimeout(() => {
const userData = { id: userId, name: '张三', email: 'zhangsan@example.com' };
callback(null, userData); // 错误优先的回调约定
}, 1000);
}
// 使用回调
fetchUserData(123, (error, data) => {
if (error) {
console.error('获取用户数据失败:', error);
} else {
console.log('用户数据:', data);
}
});
// 回调地狱示例
fetchUserData(123, (error, user) => {
if (error) {
console.error(error);
} else {
fetchUserPosts(user.id, (error, posts) => {
if (error) {
console.error(error);
} else {
fetchPostComments(posts[0].id, (error, comments) => {
if (error) {
console.error(error);
} else {
fetchCommentReplies(comments[0].id, (error, replies) => {
if (error) {
console.error(error);
} else {
console.log('最终数据:', replies);
}
});
}
});
}
});
}
});
Promise是异步编程的一种解决方案,代表了一个异步操作的最终完成或失败。
初始状态,既没有被fulfilled,也没有被rejected
操作成功完成
操作失败
// 创建Promise
const myPromise = new Promise((resolve, reject) => {
// 异步操作
const success = Math.random() > 0.5;
setTimeout(() => {
if (success) {
resolve('操作成功!'); // 成功时调用resolve
} else {
reject(new Error('操作失败!')); // 失败时调用reject
}
}, 1000);
});
// 使用Promise
myPromise
.then(result => {
console.log('成功:', result);
})
.catch(error => {
console.error('失败:', error.message);
});
// Promise快捷方法
const resolvedPromise = Promise.resolve('立即成功');
const rejectedPromise = Promise.reject(new Error('立即失败'));
// Promise链式调用
function fetchUser(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, name: '张三', departmentId: 1 });
}, 500);
});
}
function fetchDepartment(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, name: '技术部' });
}, 300);
});
}
function fetchProjects(departmentId) {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ id: 1, name: '项目A' },
{ id: 2, name: '项目B' }
]);
}, 400);
});
}
// 链式调用解决回调地狱
fetchUser(123)
.then(user => {
console.log('用户信息:', user);
return fetchDepartment(user.departmentId);
})
.then(department => {
console.log('部门信息:', department);
return fetchProjects(department.id);
})
.then(projects => {
console.log('项目列表:', projects);
})
.catch(error => {
console.error('链式调用出错:', error);
});
// Promise.all - 等待所有Promise完成
const promise1 = Promise.resolve(3);
const promise2 = new Promise(resolve => setTimeout(() => resolve('foo'), 1000));
const promise3 = Promise.resolve(42);
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log('Promise.all结果:', values); // [3, "foo", 42]
});
// Promise.allSettled - 等待所有Promise结束(无论成功失败)
const promiseA = Promise.resolve('成功A');
const promiseB = Promise.reject('失败B');
const promiseC = Promise.resolve('成功C');
Promise.allSettled([promiseA, promiseB, promiseC])
.then(results => {
console.log('Promise.allSettled结果:', results);
// [
// { status: 'fulfilled', value: '成功A' },
// { status: 'rejected', reason: '失败B' },
// { status: 'fulfilled', value: '成功C' }
// ]
});
// Promise.race - 返回最先完成的Promise
const fast = new Promise(resolve => setTimeout(() => resolve('快'), 100));
const slow = new Promise(resolve => setTimeout(() => resolve('慢'), 500));
Promise.race([fast, slow])
.then(value => {
console.log('Promise.race结果:', value); // "快"
});
// Promise.any - 返回最先成功的Promise (ES2021)
const failFast = Promise.reject('快速失败');
const succeedSlow = new Promise(resolve => setTimeout(() => resolve('慢速成功'), 300));
Promise.any([failFast, succeedSlow])
.then(value => {
console.log('Promise.any结果:', value); // "慢速成功"
})
.catch(error => {
console.log('所有Promise都失败了:', error);
});
// Promise错误处理
function riskyOperation() {
return new Promise((resolve, reject) => {
const random = Math.random();
setTimeout(() => {
if (random > 0.7) {
resolve('操作成功');
} else if (random > 0.4) {
reject(new Error('网络错误'));
} else {
throw new Error('未知错误'); // 同步错误也会被捕获
}
}, 500);
});
}
// 错误处理方式1:使用catch
riskyOperation()
.then(result => {
console.log('成功:', result);
})
.catch(error => {
console.error('捕获错误:', error.message);
});
// 错误处理方式2:使用then的第二个参数
riskyOperation()
.then(
result => console.log('成功:', result),
error => console.error('失败:', error.message)
);
// 错误处理方式3:使用finally
riskyOperation()
.then(result => console.log('成功:', result))
.catch(error => console.error('失败:', error.message))
.finally(() => console.log('操作完成')); // 无论成功失败都会执行
// 链式调用中的错误传播
Promise.resolve('开始')
.then(value => {
console.log('步骤1:', value);
throw new Error('步骤1出错');
})
.then(value => {
// 这里不会执行
console.log('步骤2:', value);
return '步骤2完成';
})
.catch(error => {
console.error('捕获错误:', error.message);
return '错误已处理'; // 返回值会传递给下一个then
})
.then(value => {
console.log('恢复处理:', value); // 会执行
});
创建一个模拟的API调用函数,实现以下功能:
async/await是ES2017引入的语法糖,让异步代码看起来像同步代码。
function fetchUserData() {
return fetchUser(123)
.then(user => {
console.log('用户:', user);
return fetchPosts(user.id);
})
.then(posts => {
console.log('文章:', posts);
return fetchComments(posts[0].id);
})
.then(comments => {
console.log('评论:', comments);
return comments;
})
.catch(error => {
console.error('错误:', error);
throw error;
});
}
async function fetchUserData() {
try {
const user = await fetchUser(123);
console.log('用户:', user);
const posts = await fetchPosts(user.id);
console.log('文章:', posts);
const comments = await fetchComments(posts[0].id);
console.log('评论:', comments);
return comments;
} catch (error) {
console.error('错误:', error);
throw error;
}
}
// async函数总是返回Promise
async function basicExample() {
// await只能在async函数中使用
const result = await Promise.resolve('Hello');
return result + ' World'; // 返回值会被包装成Promise
}
// 调用async函数
basicExample().then(result => {
console.log(result); // "Hello World"
});
// 立即执行的async函数
(async () => {
const data = await fetch('/api/data');
console.log(await data.json());
})();
// async函数中的返回值
async function returnExample() {
return 'direct return'; // 等同于 Promise.resolve('direct return')
}
async function throwExample() {
throw new Error('async error'); // 等同于 Promise.reject(new Error('async error'))
}
// 等待非Promise值
async function awaitNonPromise() {
const immediate = await 'immediate value'; // 立即返回
const number = await 42; // 立即返回
console.log(immediate, number);
}
// 串行执行(顺序等待)
async function serialExecution() {
console.log('开始串行执行');
const start = Date.now();
const result1 = await delay(1000, 'task1');
console.log('任务1完成:', result1);
const result2 = await delay(1000, 'task2');
console.log('任务2完成:', result2);
const result3 = await delay(1000, 'task3');
console.log('任务3完成:', result3);
console.log('串行总时间:', Date.now() - start, 'ms'); // 约3000ms
}
// 并行执行(同时开始)
async function parallelExecution() {
console.log('开始并行执行');
const start = Date.now();
// 同时启动所有任务
const promise1 = delay(1000, 'task1');
const promise2 = delay(1000, 'task2');
const promise3 = delay(1000, 'task3');
// 等待所有任务完成
const results = await Promise.all([promise1, promise2, promise3]);
console.log('所有任务完成:', results);
console.log('并行总时间:', Date.now() - start, 'ms'); // 约1000ms
}
// 使用Promise.allSettled处理可能失败的并行任务
async function parallelWithErrorHandling() {
const tasks = [
delay(500, 'success1'),
delay(800, 'success2'),
Promise.reject(new Error('task3 failed')),
delay(300, 'success4')
];
const results = await Promise.allSettled(tasks);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`任务${index + 1}成功:`, result.value);
} else {
console.log(`任务${index + 1}失败:`, result.reason.message);
}
});
}
// 辅助函数
function delay(ms, value) {
return new Promise(resolve => setTimeout(() => resolve(value), ms));
}
// try-catch错误处理
async function errorHandlingExample() {
try {
const result = await riskyAsyncOperation();
console.log('操作成功:', result);
} catch (error) {
console.error('捕获错误:', error.message);
// 可以在这里处理错误或重新抛出
} finally {
console.log('清理操作');
}
}
// 多个await的错误处理
async function multipleAwaitError() {
try {
const user = await fetchUser(123);
const posts = await fetchPosts(user.id); // 如果这里出错
const comments = await fetchComments(posts[0].id); // 这里不会执行
return { user, posts, comments };
} catch (error) {
console.error('流程中断:', error.message);
// 决定如何处理错误
return null;
}
}
// 部分错误处理
async function partialErrorHandling() {
let user, posts, comments;
try {
user = await fetchUser(123);
} catch (error) {
console.error('获取用户失败:', error.message);
return null;
}
try {
posts = await fetchPosts(user.id);
} catch (error) {
console.error('获取文章失败,使用默认值');
posts = [];
}
try {
comments = posts.length > 0 ? await fetchComments(posts[0].id) : [];
} catch (error) {
console.error('获取评论失败,使用默认值');
comments = [];
}
return { user, posts, comments };
}
// 错误重试机制
async function withRetry(asyncFn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await asyncFn();
} catch (error) {
console.log(`尝试 ${i + 1} 失败:`, error.message);
if (i === maxRetries - 1) {
throw error; // 最后一次重试失败,抛出错误
}
await delay(1000 * (i + 1)); // 延迟重试
}
}
}
function riskyAsyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.6) {
resolve('操作成功');
} else {
reject(new Error('操作失败'));
}
}, 500);
});
}
// 在循环中使用async/await
const urls = [
'/api/users/1',
'/api/users/2',
'/api/users/3',
'/api/users/4'
];
// 错误方式:forEach不等待async函数
async function wrongWay() {
console.log('开始错误方式');
urls.forEach(async (url) => {
const data = await simulateAPICall(url);
console.log('数据:', data);
});
console.log('错误方式结束'); // 这行会立即执行
}
// 正确方式1:使用for...of(串行)
async function serialLoop() {
console.log('开始串行循环');
for (const url of urls) {
const data = await simulateAPICall(url);
console.log('串行数据:', data);
}
console.log('串行循环结束');
}
// 正确方式2:使用Promise.all(并行)
async function parallelLoop() {
console.log('开始并行循环');
const promises = urls.map(url => simulateAPICall(url));
const results = await Promise.all(promises);
results.forEach((data, index) => {
console.log(`并行数据${index + 1}:`, data);
});
console.log('并行循环结束');
}
// 正确方式3:使用传统for循环(串行)
async function traditionalLoop() {
console.log('开始传统循环');
for (let i = 0; i < urls.length; i++) {
const data = await simulateAPICall(urls[i]);
console.log(`传统循环数据${i + 1}:`, data);
}
console.log('传统循环结束');
}
// 限制并发数量
async function limitedConcurrency(urls, limit = 2) {
const results = [];
for (let i = 0; i < urls.length; i += limit) {
const batch = urls.slice(i, i + limit);
const batchPromises = batch.map(url => simulateAPICall(url));
const batchResults = await Promise.all(batchPromises);
results.push(...batchResults);
console.log(`批次 ${Math.floor(i / limit) + 1} 完成`);
}
return results;
}
// reduce中使用async/await(串行处理)
async function reduceAsync() {
const result = await urls.reduce(async (accPromise, url) => {
const acc = await accPromise;
const data = await simulateAPICall(url);
return acc + data.length;
}, Promise.resolve(0));
console.log('reduce结果:', result);
return result;
}
function simulateAPICall(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`Data from ${url}`);
}, Math.random() * 1000 + 200);
});
}
创建一个异步数据处理器,实现以下功能:
// 完整的异步数据处理器实现会在这里显示
模块化是现代JavaScript开发的重要组成部分,让代码更加组织化和可维护。
所有代码都在全局作用域,容易产生命名冲突
var myFunction = function() { };
服务端模块化标准
const module = require('module');
异步模块定义,适用于浏览器
define(['dep'], function(dep) { });
原生JavaScript模块标准
import { func } from 'module';
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
// 批量导出
const subtract = (a, b) => a - b;
const divide = (a, b) => a / b;
export { subtract, divide };
// 导出时重命名
export { subtract as minus, divide as div };
// calculator.js
class Calculator {
add(a, b) { return a + b; }
subtract(a, b) { return a - b; }
}
export default Calculator;
// 或者直接导出
export default class {
add(a, b) { return a + b; }
subtract(a, b) { return a - b; }
}
// 导出函数
export default function calculate(operation, a, b) {
switch(operation) {
case 'add': return a + b;
case 'subtract': return a - b;
default: throw new Error('Unknown operation');
}
}
// 导出值
export default 42;
// utils.js
export const VERSION = '1.0.0';
export function formatDate(date) {
return date.toLocaleDateString();
}
export class Logger {
log(message) {
console.log(`[${new Date()}] ${message}`);
}
}
// 默认导出 + 命名导出
export default {
name: 'UtilsLibrary',
version: VERSION,
formatDate,
Logger
};
// 导入特定函数
import { add, multiply } from './math.js';
// 导入并重命名
import { subtract as minus, divide as div } from './math.js';
// 导入所有命名导出
import * as MathUtils from './math.js';
console.log(MathUtils.add(2, 3)); // 5
console.log(MathUtils.PI); // 3.14159
// 混合导入
import { PI, add } from './math.js';
// 导入默认导出
import Calculator from './calculator.js';
const calc = new Calculator();
// 默认导入可以任意命名
import MyCalculator from './calculator.js';
import calc from './calculator.js';
// 导入默认导出的函数
import calculate from './calculator.js';
const result = calculate('add', 2, 3);
// 同时导入默认和命名导出
import Utils, { VERSION, formatDate, Logger } from './utils.js';
// 动态导入
const mathModule = await import('./math.js');
const result = mathModule.add(2, 3);
// 条件导入
if (condition) {
const { heavyFunction } = await import('./heavy-module.js');
heavyFunction();
}
// 仅执行模块(副作用导入)
import './polyfill.js';
import './styles.css';
// 统一导出所有组件
export { default as Button } from './Button.js';
export { default as Modal } from './Modal.js';
// 或者
import Button from './Button.js';
import Modal from './Modal.js';
export { Button, Modal };
// API服务模块
const BASE_URL = 'https://api.example.com';
class APIService {
async get(endpoint) {
const response = await fetch(`${BASE_URL}${endpoint}`);
return response.json();
}
async post(endpoint, data) {
const response = await fetch(`${BASE_URL}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
}
export default new APIService();
// 应用入口文件
import { Button, Modal } from './components/index.js';
import APIService from './services/api.js';
import { formatDate, validate } from './utils/helpers.js';
class App {
constructor() {
this.initializeComponents();
this.loadInitialData();
}
async initializeComponents() {
// 初始化组件
}
async loadInitialData() {
const data = await APIService.get('/users');
console.log('用户数据:', data);
}
}
export default App;
// logger.js - 单例模式
class Logger {
constructor() {
if (Logger.instance) {
return Logger.instance;
}
this.logs = [];
Logger.instance = this;
}
log(message) {
const timestamp = new Date().toISOString();
this.logs.push({ timestamp, message });
console.log(`[${timestamp}] ${message}`);
}
getLogs() {
return [...this.logs];
}
}
export default new Logger(); // 导出实例,确保单例
// shape-factory.js
class Circle {
constructor(radius) {
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
class ShapeFactory {
static createShape(type, ...args) {
switch (type) {
case 'circle':
return new Circle(...args);
case 'rectangle':
return new Rectangle(...args);
default:
throw new Error(`Unknown shape type: ${type}`);
}
}
}
export default ShapeFactory;
// event-emitter.js
class EventEmitter {
constructor() {
this.events = new Map();
}
on(event, callback) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event).push(callback);
}
off(event, callback) {
if (this.events.has(event)) {
const callbacks = this.events.get(event);
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
emit(event, ...args) {
if (this.events.has(event)) {
this.events.get(event).forEach(callback => {
callback(...args);
});
}
}
}
export default EventEmitter;
// config.js
const config = {
development: {
apiUrl: 'http://localhost:3000/api',
debug: true,
logLevel: 'debug'
},
production: {
apiUrl: 'https://api.production.com',
debug: false,
logLevel: 'error'
}
};
const environment = process.env.NODE_ENV || 'development';
export default config[environment];
// 使用环境变量的配置
export const API_URL = process.env.API_URL || config[environment].apiUrl;
export const DEBUG = process.env.DEBUG === 'true' || config[environment].debug;
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils')
}
}
};
// vite.config.js
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components')
}
},
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['lodash', 'axios'],
components: ['./src/components/index.js']
}
}
}
}
});
// 良好的Tree Shaking写法
// utils.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
// main.js - 只导入需要的函数
import { add, multiply } from './utils.js';
// 避免的写法
// import * as utils from './utils.js'; // 会导入所有函数
// const result = utils.add(1, 2);
// package.json设置
{
"sideEffects": false, // 标记为无副作用,可以安全地Tree Shake
"sideEffects": ["*.css", "./src/polyfills.js"] // 指定有副作用的文件
}
// 根据条件动态加载模块
async function handleFeature() {
if (userHasPermission) {
const { AdminPanel } = await import('./AdminPanel.js');
new AdminPanel().render();
}
}
// 路由懒加载
const routes = {
'/home': () => import('./pages/Home.js'),
'/about': () => import('./pages/About.js'),
'/contact': () => import('./pages/Contact.js')
};
async function navigateTo(path) {
const pageModule = await routes[path]();
const Page = pageModule.default;
new Page().render();
}
// 懒加载组件
class LazyComponent {
constructor(selector, importFn) {
this.selector = selector;
this.importFn = importFn;
this.loaded = false;
this.setupIntersectionObserver();
}
setupIntersectionObserver() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && !this.loaded) {
this.loadComponent();
}
});
});
const element = document.querySelector(this.selector);
if (element) {
observer.observe(element);
}
}
async loadComponent() {
try {
this.loaded = true;
const module = await this.importFn();
const Component = module.default;
new Component().render(this.selector);
} catch (error) {
console.error('组件加载失败:', error);
}
}
}
// 使用懒加载组件
new LazyComponent('.chart-container', () => import('./Chart.js'));
new LazyComponent('.map-container', () => import('./Map.js'));
// 模块预加载策略
class ModulePreloader {
constructor() {
this.preloadedModules = new Map();
}
// 预加载模块
async preload(moduleMap) {
const promises = Object.entries(moduleMap).map(async ([name, importFn]) => {
try {
const module = await importFn();
this.preloadedModules.set(name, module);
console.log(`模块 ${name} 预加载完成`);
} catch (error) {
console.error(`模块 ${name} 预加载失败:`, error);
}
});
await Promise.allSettled(promises);
}
// 获取预加载的模块
getModule(name) {
return this.preloadedModules.get(name);
}
// 智能预加载(基于用户行为)
intelligentPreload() {
// 鼠标悬停预加载
document.addEventListener('mouseover', (e) => {
const link = e.target.closest('[data-preload]');
if (link) {
const moduleName = link.dataset.preload;
this.preloadIfNotLoaded(moduleName);
}
});
// 空闲时间预加载
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
this.preloadNonCriticalModules();
});
}
}
}
// 使用预加载器
const preloader = new ModulePreloader();
preloader.preload({
chart: () => import('./Chart.js'),
editor: () => import('./Editor.js'),
dashboard: () => import('./Dashboard.js')
});
项目:创建一个模块化的任务管理应用
src/ ├── core/ │ ├── TaskManager.js // 任务管理核心 │ ├── EventEmitter.js // 事件系统 │ └── Storage.js // 存储服务 ├── components/ │ ├── TaskList.js // 任务列表组件 │ ├── TaskForm.js // 任务表单组件 │ ├── CategoryFilter.js // 分类过滤组件 │ └── index.js // 组件统一导出 ├── services/ │ ├── api.js // API服务 │ ├── import-export.js // 导入导出功能 │ └── analytics.js // 数据分析 ├── utils/ │ ├── validators.js // 数据验证 │ ├── formatters.js // 数据格式化 │ └── constants.js // 常量定义 └── main.js // 应用入口
掌握这些高级技巧,让你的JavaScript代码更加优雅和高效。
函数式编程强调使用纯函数和不可变数据,让代码更可预测和易于测试。
// 纯函数:相同输入总是产生相同输出,无副作用
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
// 高阶函数
function createMultiplier(factor) {
return function(num) {
return num * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
// 依赖外部状态
let counter = 0;
function impureIncrement() {
return ++counter; // 副作用:修改外部变量
}
// 随机性
function impureRandom() {
return Math.random(); // 相同输入产生不同输出
}
// 修改输入参数
function impureSort(array) {
return array.sort(); // 副作用:修改原数组
}
// 函数组合 - 将多个函数组合成一个函数
const compose = (...functions) => (value) =>
functions.reduceRight((acc, fn) => fn(acc), value);
const pipe = (...functions) => (value) =>
functions.reduce((acc, fn) => fn(acc), value);
// 示例函数
const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;
// 使用compose(从右到左)
const addOneDoubleSquare = compose(square, double, addOne);
console.log(addOneDoubleSquare(3)); // square(double(addOne(3))) = square(8) = 64
// 使用pipe(从左到右)
const addOneDoubleSquarePipe = pipe(addOne, double, square);
console.log(addOneDoubleSquarePipe(3)); // square(double(addOne(3))) = 64
// 柯里化:将多参数函数转换为单参数函数序列
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
}
};
}
// 原始函数
function add(a, b, c) {
return a + b + c;
}
// 柯里化版本
const curriedAdd = curry(add);
// 多种调用方式
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
console.log(curriedAdd(1, 2, 3)); // 6
// 实用的柯里化示例
const multiply = curry((a, b) => a * b);
const double = multiply(2);
const triple = multiply(3);
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.map(double)); // [2, 4, 6, 8, 10]
console.log(numbers.map(triple)); // [3, 6, 9, 12, 15]
// 函数式编程风格的数组操作
const users = [
{ name: '张三', age: 25, department: 'IT', salary: 8000 },
{ name: '李四', age: 30, department: 'HR', salary: 7000 },
{ name: '王五', age: 35, department: 'IT', salary: 12000 },
{ name: '赵六', age: 28, department: 'Finance', salary: 9000 }
];
// 函数式风格:链式操作
const result = users
.filter(user => user.department === 'IT') // 筛选IT部门
.map(user => ({ ...user, bonus: user.salary * 0.1 })) // 添加奖金
.sort((a, b) => b.salary - a.salary) // 按薪资降序
.slice(0, 2); // 取前2名
console.log(result);
// 自定义函数式工具
const pipe = (...fns) => value => fns.reduce((acc, fn) => fn(acc), value);
const filterIT = users => users.filter(user => user.department === 'IT');
const addBonus = users => users.map(user => ({ ...user, bonus: user.salary * 0.1 }));
const sortBySalary = users => [...users].sort((a, b) => b.salary - a.salary);
const takeTwo = users => users.slice(0, 2);
const processUsers = pipe(filterIT, addBonus, sortBySalary, takeTwo);
const processedUsers = processUsers(users);
设计模式是解决常见问题的可复用解决方案。
定义对象间的一对多依赖关系,当对象状态改变时,所有依赖它的对象都会收到通知。
// 观察者模式实现
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} 收到通知:`, data);
}
}
// 使用示例
const newsAgency = new Subject();
const tvStation = new Observer('电视台');
const newspaper = new Observer('报纸');
const website = new Observer('网站');
newsAgency.subscribe(tvStation);
newsAgency.subscribe(newspaper);
newsAgency.subscribe(website);
newsAgency.notify('重大新闻:JavaScript学习进度更新!');
// 实际应用:状态管理
class Store extends Subject {
constructor() {
super();
this.state = {};
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.notify(this.state);
}
getState() {
return this.state;
}
}
const store = new Store();
const component1 = new Observer('组件1');
const component2 = new Observer('组件2');
store.subscribe(component1);
store.subscribe(component2);
store.setState({ user: '张三', theme: 'dark' });
定义一系列算法,把它们封装起来,并且使它们可以相互替换。
// 策略模式实现
class PaymentStrategy {
pay(amount) {
throw new Error('pay method must be implemented');
}
}
class CreditCardPayment extends PaymentStrategy {
constructor(cardNumber) {
super();
this.cardNumber = cardNumber;
}
pay(amount) {
console.log(`使用信用卡 ${this.cardNumber} 支付 ${amount} 元`);
return { success: true, method: 'credit_card', amount };
}
}
class AlipayPayment extends PaymentStrategy {
constructor(account) {
super();
this.account = account;
}
pay(amount) {
console.log(`使用支付宝账户 ${this.account} 支付 ${amount} 元`);
return { success: true, method: 'alipay', amount };
}
}
class WeChatPayment extends PaymentStrategy {
constructor(phoneNumber) {
super();
this.phoneNumber = phoneNumber;
}
pay(amount) {
console.log(`使用微信账户 ${this.phoneNumber} 支付 ${amount} 元`);
return { success: true, method: 'wechat', amount };
}
}
// 支付上下文
class PaymentContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
executePayment(amount) {
return this.strategy.pay(amount);
}
}
// 使用示例
const payment = new PaymentContext(new CreditCardPayment('1234-5678-9012-3456'));
payment.executePayment(100);
// 切换策略
payment.setStrategy(new AlipayPayment('13800138000'));
payment.executePayment(200);
// 函数式策略模式
const paymentStrategies = {
creditCard: (cardNumber) => (amount) => ({
success: true,
method: 'credit_card',
message: `信用卡 ${cardNumber} 支付 ${amount} 元成功`
}),
alipay: (account) => (amount) => ({
success: true,
method: 'alipay',
message: `支付宝 ${account} 支付 ${amount} 元成功`
}),
wechat: (phone) => (amount) => ({
success: true,
method: 'wechat',
message: `微信 ${phone} 支付 ${amount} 元成功`
})
};
const processPayment = (strategy, config, amount) => {
return paymentStrategies[strategy](config)(amount);
};
动态地给对象添加新功能,而不改变其结构。
// 装饰器模式实现
class Coffee {
cost() {
return 10;
}
description() {
return '咖啡';
}
}
// 装饰器基类
class CoffeeDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
description() {
return this.coffee.description();
}
}
// 具体装饰器
class MilkDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 2;
}
description() {
return this.coffee.description() + ' + 牛奶';
}
}
class SugarDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 1;
}
description() {
return this.coffee.description() + ' + 糖';
}
}
class VanillaDecorator extends CoffeeDecorator {
cost() {
return this.coffee.cost() + 3;
}
description() {
return this.coffee.description() + ' + 香草';
}
}
// 使用装饰器
let myCoffee = new Coffee();
console.log(`${myCoffee.description()}: ${myCoffee.cost()}元`);
myCoffee = new MilkDecorator(myCoffee);
console.log(`${myCoffee.description()}: ${myCoffee.cost()}元`);
myCoffee = new SugarDecorator(myCoffee);
console.log(`${myCoffee.description()}: ${myCoffee.cost()}元`);
myCoffee = new VanillaDecorator(myCoffee);
console.log(`${myCoffee.description()}: ${myCoffee.cost()}元`);
// 函数式装饰器
const withLogging = (fn) => {
return function(...args) {
console.log(`调用函数 ${fn.name},参数:`, args);
const result = fn.apply(this, args);
console.log(`函数 ${fn.name} 返回:`, result);
return result;
};
};
const withTiming = (fn) => {
return function(...args) {
const start = performance.now();
const result = fn.apply(this, args);
const end = performance.now();
console.log(`函数 ${fn.name} 执行时间: ${end - start}ms`);
return result;
};
};
// 使用函数装饰器
function calculate(a, b) {
return a * b + Math.random();
}
const decoratedCalculate = withTiming(withLogging(calculate));
decoratedCalculate(5, 10);
为其他对象提供一种代理以控制对这个对象的访问。
// 使用ES6 Proxy实现代理模式
class DatabaseService {
constructor() {
this.data = {
users: [
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' }
]
};
}
getUser(id) {
console.log(`从数据库获取用户 ${id}`);
return this.data.users.find(user => user.id === id);
}
getAllUsers() {
console.log('从数据库获取所有用户');
return this.data.users;
}
}
// 缓存代理
class CachedDatabaseService {
constructor(databaseService) {
this.databaseService = databaseService;
this.cache = new Map();
return new Proxy(this, {
get(target, prop) {
if (prop === 'getUser') {
return function(id) {
const cacheKey = `user_${id}`;
if (target.cache.has(cacheKey)) {
console.log(`从缓存获取用户 ${id}`);
return target.cache.get(cacheKey);
}
const user = target.databaseService.getUser(id);
target.cache.set(cacheKey, user);
return user;
};
}
if (prop === 'getAllUsers') {
return function() {
const cacheKey = 'all_users';
if (target.cache.has(cacheKey)) {
console.log('从缓存获取所有用户');
return target.cache.get(cacheKey);
}
const users = target.databaseService.getAllUsers();
target.cache.set(cacheKey, users);
return users;
};
}
return target[prop];
}
});
}
}
// 权限代理
const createSecureProxy = (target, permissions) => {
return new Proxy(target, {
get(obj, prop) {
if (!permissions.includes(prop)) {
throw new Error(`没有权限访问 ${prop}`);
}
return obj[prop];
},
set(obj, prop, value) {
if (!permissions.includes(`set_${prop}`)) {
throw new Error(`没有权限设置 ${prop}`);
}
obj[prop] = value;
return true;
}
});
};
// 验证代理
const createValidationProxy = (target, validators) => {
return new Proxy(target, {
set(obj, prop, value) {
if (validators[prop] && !validators[prop](value)) {
throw new Error(`${prop} 的值 ${value} 不合法`);
}
obj[prop] = value;
return true;
}
});
};
// 使用示例
const db = new DatabaseService();
const cachedDb = new CachedDatabaseService(db);
// 第一次调用,从数据库获取
cachedDb.getUser(1);
// 第二次调用,从缓存获取
cachedDb.getUser(1);
// 权限控制示例
const sensitiveData = { secret: 'top-secret', public: 'everyone-can-see' };
const secureData = createSecureProxy(sensitiveData, ['public']);
try {
console.log(secureData.public); // 正常访问
console.log(secureData.secret); // 抛出错误
} catch (error) {
console.error(error.message);
}
// 数据验证示例
const user = {};
const validatedUser = createValidationProxy(user, {
email: value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
age: value => typeof value === 'number' && value > 0 && value < 150
});
try {
validatedUser.email = 'test@example.com'; // 正常
validatedUser.age = 25; // 正常
validatedUser.age = -5; // 抛出错误
} catch (error) {
console.error(error.message);
}
了解这些性能优化技巧,让你的JavaScript代码运行更快。
// 防抖:延迟执行,如果在延迟时间内再次触发,则重新计时
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 节流:固定时间间隔内只执行一次
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用示例
const expensiveOperation = () => {
console.log('执行昂贵操作');
// 模拟昂贵操作
for (let i = 0; i < 1000000; i++) {
Math.random();
}
};
const debouncedOperation = debounce(expensiveOperation, 300);
const throttledOperation = throttle(expensiveOperation, 300);
// 搜索框防抖
const searchInput = document.querySelector('#search');
const debouncedSearch = debounce((query) => {
console.log('搜索:', query);
// 发送搜索请求
}, 300);
searchInput?.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
// 滚动事件节流
const throttledScroll = throttle(() => {
console.log('滚动事件处理');
// 处理滚动逻辑
}, 100);
window.addEventListener('scroll', throttledScroll);
// 记忆化缓存
const memoize = (fn) => {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('从缓存返回结果');
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
};
// 斐波那契数列(带缓存)
const fibonacci = memoize((n) => {
console.log(`计算 fibonacci(${n})`);
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
// LRU缓存实现
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (this.cache.has(key)) {
// 移动到最新位置
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
return -1;
}
set(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
// 删除最久未使用的项
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}
// HTTP请求缓存
class HTTPCache {
constructor(ttl = 5 * 60 * 1000) { // 默认5分钟过期
this.cache = new Map();
this.ttl = ttl;
}
async fetch(url, options = {}, useCache = true) {
const cacheKey = `${url}_${JSON.stringify(options)}`;
if (useCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.ttl) {
console.log('使用缓存数据');
return cached.data;
} else {
this.cache.delete(cacheKey);
}
}
console.log('发送HTTP请求');
const response = await fetch(url, options);
const data = await response.json();
if (useCache) {
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
}
return data;
}
}
const httpCache = new HTTPCache();
// httpCache.fetch('/api/users');
// 虚拟滚动实现(适用于大数据列表)
class VirtualScroll {
constructor(container, items, itemHeight, visibleCount) {
this.container = container;
this.items = items;
this.itemHeight = itemHeight;
this.visibleCount = visibleCount;
this.startIndex = 0;
this.endIndex = visibleCount;
this.setupContainer();
this.render();
this.bindEvents();
}
setupContainer() {
this.container.style.overflow = 'auto';
this.container.style.height = `${this.visibleCount * this.itemHeight}px`;
// 创建滚动容器
this.scrollContainer = document.createElement('div');
this.scrollContainer.style.height = `${this.items.length * this.itemHeight}px`;
this.scrollContainer.style.position = 'relative';
// 创建可见项容器
this.visibleContainer = document.createElement('div');
this.visibleContainer.style.position = 'absolute';
this.visibleContainer.style.width = '100%';
this.scrollContainer.appendChild(this.visibleContainer);
this.container.appendChild(this.scrollContainer);
}
render() {
// 清空容器
this.visibleContainer.innerHTML = '';
// 只渲染可见项
for (let i = this.startIndex; i < this.endIndex && i < this.items.length; i++) {
const item = document.createElement('div');
item.style.height = `${this.itemHeight}px`;
item.style.position = 'absolute';
item.style.top = `${i * this.itemHeight}px`;
item.style.width = '100%';
item.textContent = this.items[i];
item.style.borderBottom = '1px solid #eee';
item.style.display = 'flex';
item.style.alignItems = 'center';
item.style.padding = '0 10px';
this.visibleContainer.appendChild(item);
}
console.log(`渲染项目 ${this.startIndex} 到 ${this.endIndex - 1}`);
}
bindEvents() {
this.container.addEventListener('scroll', () => {
const scrollTop = this.container.scrollTop;
const newStartIndex = Math.floor(scrollTop / this.itemHeight);
const newEndIndex = Math.min(
newStartIndex + this.visibleCount + 1,
this.items.length
);
if (newStartIndex !== this.startIndex || newEndIndex !== this.endIndex) {
this.startIndex = newStartIndex;
this.endIndex = newEndIndex;
this.render();
}
});
}
}
// 生成大量测试数据
const generateLargeDataset = (count) => {
return Array.from({ length: count }, (_, i) => `列表项 ${i + 1}`);
};
// 使用虚拟滚动
const largeDataset = generateLargeDataset(10000);
// const virtualList = new VirtualScroll(
// document.getElementById('virtual-list'),
// largeDataset,
// 50, // 每项高度
// 20 // 可见项数量
// );
// Web Workers用于CPU密集型任务
class WorkerPool {
constructor(workerScript, poolSize = 4) {
this.workerScript = workerScript;
this.poolSize = poolSize;
this.workers = [];
this.taskQueue = [];
this.busyWorkers = new Set();
this.initWorkers();
}
initWorkers() {
for (let i = 0; i < this.poolSize; i++) {
const worker = new Worker(this.workerScript);
worker.id = i;
worker.onmessage = (e) => {
this.handleWorkerMessage(worker, e);
};
worker.onerror = (error) => {
console.error(`Worker ${worker.id} 错误:`, error);
};
this.workers.push(worker);
}
}
handleWorkerMessage(worker, e) {
const { taskId, result, error } = e.data;
// 从忙碌列表中移除
this.busyWorkers.delete(worker);
// 查找对应的任务回调
const taskIndex = this.taskQueue.findIndex(task => task.id === taskId);
if (taskIndex !== -1) {
const task = this.taskQueue.splice(taskIndex, 1)[0];
if (error) {
task.reject(new Error(error));
} else {
task.resolve(result);
}
}
// 处理队列中的下一个任务
this.processNextTask();
}
execute(data) {
return new Promise((resolve, reject) => {
const taskId = Date.now() + Math.random();
const task = { id: taskId, data, resolve, reject };
// 寻找空闲worker
const availableWorker = this.workers.find(worker =>
!this.busyWorkers.has(worker)
);
if (availableWorker) {
this.assignTask(availableWorker, task);
} else {
// 添加到队列
this.taskQueue.push(task);
}
});
}
assignTask(worker, task) {
this.busyWorkers.add(worker);
worker.postMessage({
taskId: task.id,
data: task.data
});
}
processNextTask() {
if (this.taskQueue.length > 0) {
const availableWorker = this.workers.find(worker =>
!this.busyWorkers.has(worker)
);
if (availableWorker) {
const task = this.taskQueue.shift();
this.assignTask(availableWorker, task);
}
}
}
terminate() {
this.workers.forEach(worker => worker.terminate());
this.workers = [];
this.taskQueue = [];
this.busyWorkers.clear();
}
}
// Worker脚本内容(通常是单独的文件)
const workerScriptContent = `
self.onmessage = function(e) {
const { taskId, data } = e.data;
try {
// 执行CPU密集型任务
const result = performHeavyCalculation(data);
self.postMessage({
taskId,
result
});
} catch (error) {
self.postMessage({
taskId,
error: error.message
});
}
};
function performHeavyCalculation(data) {
// 模拟复杂计算
const { start, end } = data;
let sum = 0;
for (let i = start; i <= end; i++) {
sum += Math.sqrt(i) * Math.sin(i);
}
return sum;
}
`;
// 创建Blob URL作为Worker脚本
const createWorkerFromScript = (scriptContent) => {
const blob = new Blob([scriptContent], { type: 'application/javascript' });
return URL.createObjectURL(blob);
};
// 使用Worker Pool
async function demonstrateWorkerPool() {
const workerUrl = createWorkerFromScript(workerScriptContent);
const workerPool = new WorkerPool(workerUrl, 2);
const tasks = [
{ start: 1, end: 100000 },
{ start: 100001, end: 200000 },
{ start: 200001, end: 300000 },
{ start: 300001, end: 400000 }
];
console.log('开始并行计算...');
const startTime = performance.now();
try {
const results = await Promise.all(
tasks.map(task => workerPool.execute(task))
);
const endTime = performance.now();
console.log('计算结果:', results);
console.log(`总耗时: ${endTime - startTime}ms`);
} catch (error) {
console.error('计算失败:', error);
} finally {
workerPool.terminate();
URL.revokeObjectURL(workerUrl);
}
}
运用所学的所有JavaScript进阶技术,构建一个完整的数据可视化应用。
运用所学的所有JavaScript进阶技术,从零开始构建一个完整的项目作品集网站:
建议完成时间:2-4周
评估标准:代码质量、功能完整性、用户体验、创新性
恭喜您完成了JavaScript进阶课程学习