🚀 ES6特性全攻略:让你的JavaScript代码更优雅

ES6(ECMAScript 2015)是JavaScript历史上最重要的更新之一,它不仅带来了语法糖,更重要的是改变了我们编写JavaScript的思维方式。本文将通过生动的例子和实际场景,带你领略ES6的魅力!

一、变量声明革命:告别var的混乱时代 🌟

还记得那些被var坑过的日子吗?变量提升、作用域混乱…ES6的letconst终于拯救了我们!

1
2
3
4
5
6
7
8
9
10
// 经典的var坑:循环中的异步回调
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出 3, 3, 3 😱
}, 100);
}

// 变量提升导致的困惑
console.log(name); // undefined(而不是报错)
var name = "Alice";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// let解决循环问题
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出 0, 1, 2 ✨
}, 100);
}

// 暂时性死区保护
console.log(age); // ReferenceError: 提前发现错误
let age = 25;

// const保证不可变
const API_URL = "https://api.example.com";
// API_URL = "other"; // TypeError: 编译时就能发现错误

最佳实践:默认使用const,需要重新赋值时才用let,彻底告别var

二、解构赋值:数据提取的艺术 🎯

想象一下,你是一个快递员,需要从包裹中取出不同的物品。解构赋值就像是给你一个神奇的工具,让你一次性精准地取出所需的东西!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 🎮 游戏开发:处理坐标
const position = [100, 200, 50]; // x, y, z
const [x, y, z = 0] = position; // 默认值很贴心

// 🔄 变量交换(告别临时变量)
let a = 1, b = 2;
[a, b] = [b, a]; // 一行搞定!

// 📊 数据分析:提取统计信息
const scores = [95, 87, 92, 78, 88];
const [highest, ...others] = scores.sort((a, b) => b - a);
console.log(`最高分: ${highest}, 其他: ${others}`);

// 🎯 函数返回多个值
function getNameAndAge() {
return ["Alice", 25];
}
const [name, age] = getNameAndAge();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 🌐 API响应处理
const response = {
data: {
user: {
id: 1,
profile: {
name: "Bob",
avatar: "avatar.jpg"
}
}
},
status: 200
};

// 深度解构 + 重命名 + 默认值
const {
data: {
user: {
profile: {
name: userName,
avatar: userAvatar = "default.jpg"
}
}
},
status = 500
} = response;

// 🎨 React组件props解构
function UserCard({ name, age, avatar = "default.jpg", ...otherProps }) {
return `<div>Hello ${name}, ${age} years old</div>`;
}

// 📱 配置对象处理
const config = {
theme: "dark",
language: "zh-CN",
notifications: true
};

const { theme, ...settings } = config;

解构赋值的超能力

  • 🚀 让代码更简洁易读
  • 🎯 精准提取所需数据
  • 🛡️ 提供默认值保护
  • 🔄 轻松实现变量交换

三、模板字符串:告别字符串拼接地狱 🎨

还在用+号拼接字符串?还在为换行而烦恼?模板字符串来拯救你了!它不仅仅是语法糖,更是字符串处理的革命。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 😫 传统方式:痛苦的拼接
const name = "Alice";
const age = 25;
const oldWay = "Hello, " + name + "!\n" +
"You are " + age + " years old.\n" +
"Today is " + new Date().toLocaleDateString();

// ✨ 模板字符串:优雅简洁
const newWay = `Hello, ${name}!
You are ${age} years old.
Today is ${new Date().toLocaleDateString()}`;

// 🧮 表达式计算
const price = 99.9;
const tax = 0.1;
const receipt = `
商品价格: ¥${price}
税费: ¥${(price * tax).toFixed(2)}
总计: ¥${(price * (1 + tax)).toFixed(2)}
`;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 🌐 动态HTML生成
function createUserCard(user) {
return `
<div class="user-card ${user.isVip ? 'vip' : 'normal'}">
<img src="${user.avatar}" alt="${user.name}">
<h3>${user.name}</h3>
<p>积分: ${user.points.toLocaleString()}</p>
${user.isVip ? '<span class="vip-badge">VIP</span>' : ''}
</div>
`;
}

// 📧 邮件模板
function generateEmail(order) {
return `
亲爱的 ${order.customerName}

您的订单 #${order.id} 已确认!

订单详情:
${order.items.map(item =>
`- ${item.name} x${item.quantity} = ¥${item.total}`
).join('\n ')}

总金额:¥${order.total}
预计送达:${order.deliveryDate}

感谢您的购买!
`;
}

// 🔍 SQL查询构建
function buildQuery(table, conditions) {
const whereClause = Object.entries(conditions)
.map(([key, value]) => `${key} = '${value}'`)
.join(' AND ');

return `
SELECT * FROM ${table}
WHERE ${whereClause}
ORDER BY created_at DESC
LIMIT 10;
`;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 🏷️ 标签模板(Tagged Templates)
function highlight(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? `<mark>${values[i]}</mark>` : '';
return result + string + value;
}, '');
}

const searchTerm = "JavaScript";
const text = highlight`学习 ${searchTerm} 是前端开发的必经之路`;
// 输出: "学习 <mark>JavaScript</mark> 是前端开发的必经之路"

// 🎨 CSS-in-JS样式
function createStyles(theme) {
return `
.button {
background: ${theme.primary};
color: ${theme.text};
border-radius: ${theme.borderRadius}px;
padding: ${theme.spacing * 2}px ${theme.spacing * 3}px;
transition: all 0.3s ease;
}

.button:hover {
background: ${theme.primaryHover};
transform: translateY(-2px);
}
`;
}

模板字符串的魔法

  • 🎯 表达式插值:${expression}
  • 📝 多行字符串:自然换行
  • 🏷️ 标签模板:自定义处理逻辑
  • 🎨 动态内容:完美适配现代开发

四、展开运算符:三个点的无限可能 🌟

三个小点...,却有着巨大的能量!展开运算符就像是数据世界的瑞士军刀,一个工具解决多种问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 🔗 数组合并:告别concat
const fruits = ['🍎', '🍌'];
const vegetables = ['🥕', '🥬'];
const food = [...fruits, '🍖', ...vegetables]; // ['🍎', '🍌', '🍖', '🥕', '🥬']

// 📋 数组复制:真正的浅拷贝
const original = [1, 2, 3];
const copy = [...original]; // 不是引用,是新数组!

// 🎯 找最值:配合Math函数
const scores = [89, 95, 76, 92, 88];
const highest = Math.max(...scores); // 95
const lowest = Math.min(...scores); // 76

// 🔄 数组去重:配合Set
const numbers = [1, 2, 2, 3, 3, 4];
const unique = [...new Set(numbers)]; // [1, 2, 3, 4]

// ➕ 数组插入:在任意位置
const list = ['a', 'b', 'e'];
const newList = ['a', 'b', 'c', 'd', 'e'];
// 等同于:list.splice(2, 0, 'c', 'd') 但更函数式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 🏗️ 对象合并:优雅的配置覆盖
const defaultConfig = {
theme: 'light',
language: 'en',
autoSave: true,
timeout: 5000
};

const userConfig = {
theme: 'dark',
timeout: 10000
};

const finalConfig = { ...defaultConfig, ...userConfig };
// { theme: 'dark', language: 'en', autoSave: true, timeout: 10000 }

// 🎨 条件属性:动态对象构建
function createUser(name, age, isAdmin = false) {
return {
name,
age,
createdAt: new Date(),
...(isAdmin && { role: 'admin', permissions: ['read', 'write'] })
};
}

// 🔧 对象更新:不可变更新模式
const user = { id: 1, name: 'Alice', profile: { age: 25 } };
const updatedUser = {
...user,
profile: {
...user.profile,
age: 26,
city: 'Shanghai'
}
};

// 🗑️ 对象属性移除
const { password, ...publicUser } = user; // 移除敏感信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 📞 函数调用:数组转参数
function greet(first, second, third) {
return `Hello ${first}, ${second}, and ${third}!`;
}

const names = ['Alice', 'Bob', 'Charlie'];
console.log(greet(...names)); // "Hello Alice, Bob, and Charlie!"

// 🎯 剩余参数:收集多余参数
function sum(first, ...rest) {
console.log('第一个:', first); // 1
console.log('其余的:', rest); // [2, 3, 4, 5]
return first + rest.reduce((a, b) => a + b, 0);
}

sum(1, 2, 3, 4, 5); // 15

// 🔄 参数转发:中间件模式
function middleware(fn) {
return function(...args) {
console.log('调用前处理');
const result = fn(...args);
console.log('调用后处理');
return result;
};
}

// 🎮 游戏开发:坐标计算
function movePlayer(player, ...movements) {
return movements.reduce((pos, [dx, dy]) => ({
x: pos.x + dx,
y: pos.y + dy
}), player);
}

const player = { x: 0, y: 0 };
const newPos = movePlayer(player, [1, 0], [0, 1], [-1, 0]); // {x: 0, y: 1}

展开运算符的超能力

  • 🔗 数组合并:比concat更直观
  • 📋 浅拷贝:避免引用问题
  • 🎯 参数展开:数组转参数列表
  • 🏗️ 对象合并:配置覆盖的利器
  • 🔄 不可变更新:函数式编程必备

五、可选链与空值合并:告别防御性编程 🛡️

还在写一堆if判断来防止报错?还在用||来设置默认值却被0false坑?可选链和空值合并操作符来拯救你!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 😫 传统防御性编程:冗长且易错
const user = getUser(); // 可能返回null
let city;
if (user && user.profile && user.profile.address && user.profile.address.city) {
city = user.profile.address.city;
} else {
city = '未知';
}

// ✨ 可选链:优雅简洁
const city = user?.profile?.address?.city ?? '未知';

// 🎯 API响应处理
const response = await fetch('/api/user');
const data = await response.json();

// 安全访问嵌套数据
const userName = data?.user?.profile?.name ?? '匿名用户';
const avatarUrl = data?.user?.profile?.avatar ?? '/default-avatar.png';
const permissions = data?.user?.roles?.[0]?.permissions ?? [];

// 📱 DOM操作安全访问
const button = document.querySelector('#submit-btn');
button?.addEventListener?.('click', handleClick); // 方法也可以可选调用

// 🎮 游戏开发:安全访问游戏状态
const player = game?.state?.currentLevel?.player;
const health = player?.stats?.health ?? 100;
const weapon = player?.inventory?.weapons?.[0]?.name ?? '拳头';
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 😱 ||操作符的陷阱
const config = {
theme: '', // 空字符串
count: 0, // 数字0
enabled: false, // 布尔false
timeout: null // 真正的空值
};

// 使用||会有意外结果
const theme = config.theme || 'default'; // 'default' (空字符串被误判)
const count = config.count || 10; // 10 (0被误判)
const enabled = config.enabled || true; // true (false被误判)

// ✨ ??只判断null和undefined
const theme2 = config.theme ?? 'default'; // '' (保持空字符串)
const count2 = config.count ?? 10; // 0 (保持数字0)
const enabled2 = config.enabled ?? true; // false (保持布尔false)
const timeout = config.timeout ?? 5000; // 5000 (null被替换)

// 🎨 实际应用:用户配置
function applyUserSettings(userSettings) {
const settings = {
theme: userSettings?.theme ?? 'auto',
fontSize: userSettings?.fontSize ?? 14,
notifications: userSettings?.notifications ?? true,
autoSave: userSettings?.autoSave ?? false,
language: userSettings?.language ?? navigator.language
};

return settings;
}

// 📊 数据处理:安全的数学运算
function calculateScore(data) {
const baseScore = data?.score ?? 0;
const bonus = data?.achievements?.length ?? 0;
const penalty = data?.violations?.count ?? 0;

return Math.max(0, baseScore + bonus * 10 - penalty * 5);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 🌐 React组件中的应用
function UserProfile({ user }) {
return (
<div className="user-profile">
<img
src={user?.avatar ?? '/default-avatar.png'}
alt={user?.name ?? '用户'}
/>
<h2>{user?.name ?? '匿名用户'}</h2>
<p>邮箱: {user?.email ?? '未设置'}</p>
<p>积分: {user?.points?.toLocaleString?.() ?? '0'}</p>

{/* 条件渲染也更安全 */}
{user?.isVip && <span className="vip-badge">VIP</span>}

{/* 嵌套组件传递props */}
<ContactInfo
phone={user?.contact?.phone}
address={user?.contact?.address?.street}
/>
</div>
);
}

// 📡 网络请求错误处理
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();

return {
id: data?.id ?? userId,
name: data?.profile?.name ?? '未知用户',
email: data?.contact?.email ?? null,
lastLogin: data?.activity?.lastLogin ?? new Date(),
preferences: {
theme: data?.settings?.theme ?? 'light',
language: data?.settings?.language ?? 'zh-CN',
notifications: data?.settings?.notifications ?? true
}
};
} catch (error) {
console.error('获取用户数据失败:', error);
return null;
}
}

// 🎯 表单验证:安全访问表单数据
function validateForm(formData) {
const errors = {};

if (!formData?.name?.trim?.()) {
errors.name = '姓名不能为空';
}

if (!formData?.email?.includes?.('@')) {
errors.email = '邮箱格式不正确';
}

if ((formData?.age ?? 0) < 18) {
errors.age = '年龄必须大于18岁';
}

return Object.keys(errors).length === 0 ? null : errors;
}

注意区别

  • ?. 可选链:安全访问属性/方法,遇到nullundefined就停止
  • ?? 空值合并:只有nullundefined才使用默认值
  • || 逻辑或:所有假值(false0''nullundefined)都使用默认值

最佳实践

  • 🛡️ API数据访问必用可选链
  • 🎯 配置默认值优选空值合并
  • 🚀 减少防御性代码,提高可读性
  • ⚡ 性能友好:短路求值机制

七、箭头函数:不只是语法糖 🏹

箭头函数不仅仅让代码更简洁,更重要的是它改变了this的绑定规则,解决了传统函数中this指向混乱的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// 😫 传统函数的this困扰
class Timer {
constructor() {
this.seconds = 0;
this.element = document.getElementById('timer');
}

start() {
// 传统方式:需要保存this引用
const self = this;
setInterval(function() {
self.seconds++;
self.element.textContent = self.seconds;
}, 1000);

// 或者使用bind
setInterval(function() {
this.seconds++;
this.element.textContent = this.seconds;
}.bind(this), 1000);
}
}

// ✨ 箭头函数:自动绑定外层this
class ModernTimer {
constructor() {
this.seconds = 0;
this.element = document.getElementById('timer');
}

start() {
// 箭头函数自动继承外层this
setInterval(() => {
this.seconds++;
this.element.textContent = this.seconds;
}, 1000);
}

// 事件处理也变得简单
bindEvents() {
this.element.addEventListener('click', () => {
this.reset(); // this正确指向Timer实例
});

// 多个事件处理
['mouseenter', 'mouseleave'].forEach(event => {
this.element.addEventListener(event, () => {
this.handleHover(event); // this始终正确
});
});
}
}

// 🎮 React组件中的应用
class GameComponent extends React.Component {
constructor(props) {
super(props);
this.state = { score: 0, level: 1 };
}

// 箭头函数方法:自动绑定this
handleScoreUpdate = (points) => {
this.setState(prevState => ({
score: prevState.score + points
}));
}

handleLevelUp = () => {
this.setState(prevState => ({
level: prevState.level + 1,
score: 0
}));
}

render() {
return (
<div>
<button onClick={this.handleScoreUpdate.bind(null, 10)}>
+10分
</button>
<button onClick={this.handleLevelUp}>
升级
</button>
</div>
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 🎯 数组处理:简洁优雅
const numbers = [1, 2, 3, 4, 5];

// 传统写法 vs 箭头函数
const doubled = numbers.map(function(n) { return n * 2; });
const doubledArrow = numbers.map(n => n * 2);

const evens = numbers.filter(function(n) { return n % 2 === 0; });
const evensArrow = numbers.filter(n => n % 2 === 0);

const sum = numbers.reduce(function(acc, n) { return acc + n; }, 0);
const sumArrow = numbers.reduce((acc, n) => acc + n, 0);

// 🔗 链式调用:函数式编程的美
const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.filter(n => n % 2 === 0) // 筛选偶数
.map(n => n * n) // 平方
.filter(n => n > 10) // 大于10
.reduce((sum, n) => sum + n, 0); // 求和

// 📊 数据处理管道
const processUserData = (users) =>
users
.filter(user => user.isActive)
.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`,
age: new Date().getFullYear() - user.birthYear
}))
.sort((a, b) => b.age - a.age)
.slice(0, 10);

// 🎨 高阶函数:函数工厂
const createValidator = (rule) => (value) => rule(value);
const createFormatter = (format) => (value) => format(value);

const isEmail = createValidator(email => /\S+@\S+\.\S+/.test(email));
const formatCurrency = createFormatter(amount => ${amount.toFixed(2)}`);

// 使用
const emails = ['test@example.com', 'invalid-email', 'user@domain.org'];
const validEmails = emails.filter(isEmail);

const prices = [99.9, 199.99, 299];
const formattedPrices = prices.map(formatCurrency);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// ⚠️ 箭头函数的限制

// 1. 不能作为构造函数
const Person = (name) => {
this.name = name; // TypeError: Person is not a constructor
};
// const person = new Person('Alice'); // 报错

// 2. 没有arguments对象
function traditionalFunc() {
console.log(arguments); // 可以访问arguments
}

const arrowFunc = () => {
console.log(arguments); // ReferenceError: arguments is not defined
};

// 解决方案:使用剩余参数
const arrowFuncWithRest = (...args) => {
console.log(args); // 正确的方式
};

// 3. 不适合对象方法(需要动态this时)
const obj = {
name: 'Alice',

// ❌ 错误:箭头函数this指向外层
sayHello: () => {
console.log(`Hello, ${this.name}`); // this不是obj
},

// ✅ 正确:传统函数this指向调用者
sayHi: function() {
console.log(`Hi, ${this.name}`); // this是obj
},

// ✅ 也正确:简写方法
sayGoodbye() {
console.log(`Goodbye, ${this.name}`); // this是obj
}
};

// 4. 不能使用yield(不能是生成器函数)
// const generatorArrow = () => {
// yield 1; // SyntaxError
// };

// 5. 原型方法定义需要注意
function User(name) {
this.name = name;
}

// ❌ 错误:箭头函数this不指向实例
User.prototype.getName = () => {
return this.name; // this不是User实例
};

// ✅ 正确:传统函数
User.prototype.getName = function() {
return this.name; // this是User实例
};

箭头函数使用原则

  • 回调函数:事件处理、数组方法、定时器
  • 函数式编程:map、filter、reduce等
  • 需要绑定外层this:类方法、嵌套函数
  • 对象方法:需要动态this时
  • 构造函数:需要new调用时
  • 原型方法:需要实例this时

八、模块化:告别全局变量污染 📦

ES6模块化是现代JavaScript开发的基石,它让代码组织更清晰,依赖关系更明确。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// 📁 utils/math.js - 数学工具模块
// 命名导出:可以有多个
export const PI = 3.14159;
export const E = 2.71828;

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 };

// 重命名导出
const power = (base, exponent) => Math.pow(base, exponent);
export { power as pow };

// 默认导出:每个模块只能有一个
export default class Calculator {
constructor() {
this.history = [];
}

calculate(operation, a, b) {
const result = operation(a, b);
this.history.push({ operation: operation.name, a, b, result });
return result;
}
}

// 📁 app.js - 使用模块
// 导入默认导出
import Calculator from './utils/math.js';

// 导入命名导出
import { add, multiply, PI } from './utils/math.js';

// 导入并重命名
import { pow as power } from './utils/math.js';

// 导入所有命名导出
import * as MathUtils from './utils/math.js';

// 混合导入
import Calculator, { add, PI } from './utils/math.js';

// 使用
const calc = new Calculator();
const result = calc.calculate(add, 5, 3);
console.log(`5 + 3 = ${result}`);
console.log(`π = ${PI}`);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 🚀 动态导入:按需加载,提升性能

// 1. 条件加载
async function loadFeature(featureName) {
if (featureName === 'chart') {
const { Chart } = await import('./features/chart.js');
return new Chart();
} else if (featureName === 'editor') {
const { Editor } = await import('./features/editor.js');
return new Editor();
}
}

// 2. 懒加载路由(React Router风格)
const routes = [
{
path: '/dashboard',
component: () => import('./pages/Dashboard.js')
},
{
path: '/profile',
component: () => import('./pages/Profile.js')
}
];

async function loadRoute(path) {
const route = routes.find(r => r.path === path);
if (route) {
const module = await route.component();
return module.default;
}
}

// 3. 插件系统
class PluginManager {
constructor() {
this.plugins = new Map();
}

async loadPlugin(pluginName) {
if (this.plugins.has(pluginName)) {
return this.plugins.get(pluginName);
}

try {
const module = await import(`./plugins/${pluginName}.js`);
const plugin = new module.default();
this.plugins.set(pluginName, plugin);
return plugin;
} catch (error) {
console.error(`加载插件 ${pluginName} 失败:`, error);
return null;
}
}

async executePlugin(pluginName, ...args) {
const plugin = await this.loadPlugin(pluginName);
return plugin?.execute(...args);
}
}

// 4. 国际化按需加载
class I18n {
constructor() {
this.messages = new Map();
this.currentLocale = 'zh-CN';
}

async loadLocale(locale) {
if (this.messages.has(locale)) {
return this.messages.get(locale);
}

try {
const module = await import(`./locales/${locale}.js`);
this.messages.set(locale, module.default);
return module.default;
} catch (error) {
console.warn(`加载语言包 ${locale} 失败,使用默认语言`);
return this.messages.get('zh-CN') || {};
}
}

async setLocale(locale) {
await this.loadLocale(locale);
this.currentLocale = locale;
}

async t(key) {
const messages = await this.loadLocale(this.currentLocale);
return messages[key] || key;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 🏗️ 模块设计模式与最佳实践

// 📁 services/api.js - API服务模块
class ApiService {
constructor(baseURL = '/api') {
this.baseURL = baseURL;
this.interceptors = {
request: [],
response: []
};
}

// 请求拦截器
addRequestInterceptor(interceptor) {
this.interceptors.request.push(interceptor);
}

// 响应拦截器
addResponseInterceptor(interceptor) {
this.interceptors.response.push(interceptor);
}

async request(endpoint, options = {}) {
let config = { ...options };

// 执行请求拦截器
for (const interceptor of this.interceptors.request) {
config = await interceptor(config);
}

let response = await fetch(`${this.baseURL}${endpoint}`, config);

// 执行响应拦截器
for (const interceptor of this.interceptors.response) {
response = await interceptor(response);
}

return response;
}
}

// 创建单例实例
const apiService = new ApiService();

// 添加认证拦截器
apiService.addRequestInterceptor(async (config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers = {
...config.headers,
'Authorization': `Bearer ${token}`
};
}
return config;
});

// 导出单例和类
export default apiService;
export { ApiService };

// 📁 stores/userStore.js - 状态管理模块
class UserStore {
constructor() {
this.state = {
user: null,
isLoading: false,
error: null
};
this.listeners = [];
}

subscribe(listener) {
this.listeners.push(listener);
return () => {
const index = this.listeners.indexOf(listener);
if (index > -1) {
this.listeners.splice(index, 1);
}
};
}

setState(newState) {
this.state = { ...this.state, ...newState };
this.listeners.forEach(listener => listener(this.state));
}

async login(credentials) {
this.setState({ isLoading: true, error: null });

try {
const response = await apiService.request('/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
});

const data = await response.json();

if (response.ok) {
localStorage.setItem('token', data.token);
this.setState({ user: data.user, isLoading: false });
} else {
throw new Error(data.message);
}
} catch (error) {
this.setState({ error: error.message, isLoading: false });
}
}

logout() {
localStorage.removeItem('token');
this.setState({ user: null, error: null });
}
}

export default new UserStore();

// 📁 components/UserProfile.js - 组件模块
import userStore from '../stores/userStore.js';

export default class UserProfile {
constructor(container) {
this.container = container;
this.unsubscribe = null;
this.init();
}

init() {
// 订阅状态变化
this.unsubscribe = userStore.subscribe((state) => {
this.render(state);
});

// 初始渲染
this.render(userStore.state);
}

render(state) {
if (state.isLoading) {
this.container.innerHTML = '<div>加载中...</div>';
return;
}

if (state.error) {
this.container.innerHTML = `<div class="error">${state.error}</div>`;
return;
}

if (state.user) {
this.container.innerHTML = `
<div class="user-profile">
<h2>欢迎, ${state.user.name}!</h2>
<p>邮箱: ${state.user.email}</p>
<button id="logout-btn">退出登录</button>
</div>
`;

// 绑定事件
this.container.querySelector('#logout-btn')
.addEventListener('click', () => userStore.logout());
} else {
this.container.innerHTML = '<div>请先登录</div>';
}
}

destroy() {
if (this.unsubscribe) {
this.unsubscribe();
}
}
}

模块化最佳实践

  • 🎯 单一职责:每个模块只做一件事
  • 📦 明确接口:清晰的导入导出
  • 🔄 循环依赖:避免模块间循环引用
  • 按需加载:使用动态导入优化性能
  • 🛡️ 错误处理:模块加载失败的降级方案

六、异步编程革命:从回调地狱到Promise天堂 🚀

异步编程是JavaScript的灵魂,从回调地狱到Promise,再到async/await,每一步都是质的飞跃!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 😱 回调地狱:层层嵌套的噩梦
function getUserData(userId, callback) {
getUser(userId, (err, user) => {
if (err) {
callback(err);
return;
}

getProfile(user.id, (err, profile) => {
if (err) {
callback(err);
return;
}

getPreferences(profile.id, (err, preferences) => {
if (err) {
callback(err);
return;
}

getFriends(user.id, (err, friends) => {
if (err) {
callback(err);
return;
}

// 终于到了业务逻辑...
callback(null, {
user,
profile,
preferences,
friends
});
});
});
});
});
}

// 使用起来也很痛苦
getUserData(123, (err, data) => {
if (err) {
console.error('获取用户数据失败:', err);
return;
}
console.log('用户数据:', data);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// ✨ Promise:链式调用的优雅
function getUserData(userId) {
return getUser(userId)
.then(user => {
// 并行获取多个数据
return Promise.all([
Promise.resolve(user),
getProfile(user.id),
getPreferences(user.id),
getFriends(user.id)
]);
})
.then(([user, profile, preferences, friends]) => ({
user,
profile,
preferences,
friends
}))
.catch(err => {
console.error('获取用户数据失败:', err);
throw err; // 重新抛出,让调用者处理
});
}

// 🎯 Promise的强大工具集
async function handleMultipleRequests() {
try {
// 并行执行,等待所有完成
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments()
]);

// 竞速执行,谁先完成用谁
const fastestResponse = await Promise.race([
fetchFromCDN(),
fetchFromBackup(),
fetchFromCache()
]);

// 部分失败也能继续(ES2020)
const results = await Promise.allSettled([
riskyOperation1(),
riskyOperation2(),
riskyOperation3()
]);

const successful = results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);

return { users, posts, comments, fastestResponse, successful };
} catch (error) {
console.error('批量操作失败:', error);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 🌟 async/await:同步风格写异步代码
async function getUserData(userId) {
try {
// 看起来像同步代码,实际是异步的
const user = await getUser(userId);

// 并行获取数据(注意:先启动所有Promise)
const profilePromise = getProfile(user.id);
const preferencesPromise = getPreferences(user.id);
const friendsPromise = getFriends(user.id);

// 然后等待所有结果
const [profile, preferences, friends] = await Promise.all([
profilePromise,
preferencesPromise,
friendsPromise
]);

return {
user,
profile,
preferences,
friends
};
} catch (error) {
console.error('获取用户数据失败:', error);

// 可以根据错误类型做不同处理
if (error.code === 'USER_NOT_FOUND') {
return null;
}

// 重新抛出其他错误
throw error;
}
}

// 🎮 实际应用:游戏数据加载
async function loadGameData(gameId) {
const loadingSteps = [
{ name: '加载游戏配置', fn: () => loadConfig(gameId) },
{ name: '加载关卡数据', fn: () => loadLevels(gameId) },
{ name: '加载角色数据', fn: () => loadCharacters(gameId) },
{ name: '加载音效资源', fn: () => loadAudio(gameId) },
{ name: '加载图片资源', fn: () => loadImages(gameId) }
];

const results = {};

for (const step of loadingSteps) {
try {
console.log(`开始${step.name}...`);
const startTime = Date.now();

results[step.name] = await step.fn();

const duration = Date.now() - startTime;
console.log(`${step.name}完成,耗时${duration}ms`);

// 更新加载进度
updateLoadingProgress(step.name);

} catch (error) {
console.error(`${step.name}失败:`, error);

// 某些步骤失败可以继续,某些必须停止
if (step.name === '加载游戏配置') {
throw new Error('游戏配置加载失败,无法继续');
}
}
}

return results;
}

// 🌐 网络请求封装
class ApiClient {
constructor(baseURL, timeout = 5000) {
this.baseURL = baseURL;
this.timeout = timeout;
}

async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
timeout: this.timeout,
headers: {
'Content-Type': 'application/json',
...options.headers
},
...options
};

try {
const response = await fetch(url, config);

if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}

const data = await response.json();
return data;
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('请求超时');
}
throw error;
}
}

// 便捷方法
async get(endpoint, params = {}) {
const query = new URLSearchParams(params).toString();
const url = query ? `${endpoint}?${query}` : endpoint;
return this.request(url);
}

async post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
}

异步编程最佳实践

  • 🎯 优先使用async/await:代码更直观易读
  • 合理使用Promise.all:并行执行提高性能
  • 🛡️ 错误处理要完善:try/catch + 错误分类
  • 🔄 避免在循环中await:除非需要串行执行
  • 📊 监控异步操作:超时、重试、进度反馈

异步编程进化

回调时代

特点:层层嵌套,错误处理复杂
问题:回调地狱,代码难以维护
适用:简单的异步操作

Promise时代

特点:链式调用,统一错误处理
优势:解决回调地狱,支持并行操作
工具:Promise.all、Promise.race等

async/await时代

特点:同步风格写异步代码
优势:代码直观,错误处理简单
现状:现代JavaScript的标准写法


九、事件委托 🎯

事件委托是 JavaScript 中一个经典的模式,它通过利用事件冒泡机制,让我们可以更高效地处理事件。

1
2
3
4
5
6
// 利用事件冒泡机制
document.querySelector('#list').addEventListener('click', e => {
if(e.target.matches('li.item')) { // CSS 选择器匹配
e.target.classList.toggle('active');
}
});

事件委托的优势
事件委托可以减少事件监听器的数量,提高性能。同时,它还能处理动态生成的元素。


十、作用域与闭包 🔄

闭包是 JavaScript 中一个重要的概念,它让我们可以创建私有的作用域,保护数据不受外界干扰。

1
2
3
4
5
6
7
// 闭包示例
function createCounter() {
let count = 0;
return () => ++count; // 保持对 count 的引用
}
const counter = createCounter();
console.log(counter()); // 1

闭包的用途
闭包可以用来创建私有变量和方法,避免数据被意外修改。它在实现模块化和封装时非常有用。


一、箭头函数的 this 绑定规则 🔄

箭头函数是 ES6 中对函数的一个重要改进,它的 this 绑定规则与传统函数不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 传统函数:this 由调用者决定
const obj = {
name: "Alice",
say: function() {
console.log(this.name); // 正常输出 "Alice"
}
};

// 箭头函数:this 继承自外层词法作用域(定义时的 this)
const obj2 = {
name: "Bob",
say: () => {
console.log(this.name); // 输出 undefined(外层可能是全局作用域)
}
};

// 典型应用场景:回调函数保留外层 this
class Button {
constructor() {
this.text = "Click me";
// 使用箭头函数自动绑定 this
this.element.addEventListener('click', () => {
console.log(this.text); // 正确指向 Button 实例
});
}
}

// 注意限制:
// 1. 不能作为构造函数(无 prototype)
// 2. 不能使用 arguments 对象(可用剩余参数替代)
// 3. 不适合对象方法定义(需访问实例属性时)

箭头函数的优缺点
箭头函数的词法作用域特性,让我们在回调函数中可以轻松地保留外层的 this。但它也有一些限制,比如不能作为构造函数。


二、模块化(import/export) 📦

模块化是 ES6 中一个重要的特性,它让我们可以更好地组织代码,实现模块化开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 📁 math.js
// 命名导出
export const PI = 3.14159;
export function sum(a, b) { return a + b; }

// 默认导出(一个模块只能有一个)
export default class Calculator { /* ... */ }

// 📁 app.js
// 导入方式
import Calculator, { PI, sum } from './math.js'; // 默认+命名导入
import * as MathUtils from './math.js'; // 命名空间导入

// 动态导入(按需加载)
const loadModule = async () => {
const module = await import('./math.js');
console.log(module.PI);
};

模块化的优势
模块化让代码更加模块化和可维护。通过 importexport,我们可以清晰地定义模块的接口,避免全局变量的污染。


三、Proxy/Reflect 元编程 🔄

Proxy 和 Reflect 是 ES6 中对元编程的支持,它们让我们可以更深入地控制对象的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建代理对象
const target = { name: "Alice" };
const handler = {
get(obj, prop) {
console.log(`访问属性: ${prop}`);
return Reflect.get(...arguments); // 使用 Reflect 完成默认操作
},
set(obj, prop, value) {
if (prop === 'age' && value < 0) {
throw new Error("年龄不能为负");
}
return Reflect.set(...arguments);
}
};

const proxy = new Proxy(target, handler);
proxy.name; // 控制台输出 "访问属性: name"
proxy.age = 25; // 正常
proxy.age = -5; // 抛出错误

// 典型应用场景:
// - 数据验证
// - 观察者模式(属性变更监听)
// - 实现私有属性(通过拦截访问)

Proxy 和 Reflect 的用途
Proxy 可以用来拦截和自定义对象的操作,而 Reflect 提供了默认的操作实现。它们在实现高级模式时非常有用。


四、Map/Set 数据结构 🔄

Map 和 Set 是 ES6 中新增的数据结构,它们提供了更加灵活的方式来存储和操作数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Map(键可以是任意类型)
const map = new Map();
map.set(1, "数值键");
map.set({id: 1}, "对象键");

// 遍历方式
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}

// Set(自动去重)
const uniqueNumbers = new Set([1, 2, 2, 3]); // {1, 2, 3}
uniqueNumbers.add(4).delete(1);

// 常用操作
const hasTwo = uniqueNumbers.has(2); // true
const size = uniqueNumbers.size; // 3

// 与普通对象的对比优势:
// 1. Map 有序存储,Object 无序
// 2. Map 可直接用 size 获取长度
// 3. Set 自动处理唯一值

Map 和 Set 的优势
Map 和 Set 提供了更加灵活的方式来存储和操作数据。Map 支持任意类型的键,而 Set 自动去重,这些特性在处理复杂数据时非常有用。


五、迭代器与生成器 🔄

迭代器和生成器是 ES6 中对迭代协议的支持,它们让我们可以更灵活地处理数据流。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 迭代器协议(实现 Symbol.iterator)
const customIterable = {
[Symbol.iterator]() {
let step = 0;
return {
next() {
return step < 3
? { value: step++, done: false }
: { done: true };
}
};
}
};

// 生成器函数(function*)
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}

const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2

// 应用场景:
// 1. 自定义数据结构迭代
// 2. 惰性求值(大数据分页)
// 3. 简化异步流程(配合 async/await)

迭代器和生成器的用途
迭代器和生成器让我们可以更灵活地处理数据流。生成器尤其适合处理惰性求值和复杂状态流。


九、Map与Set:数据结构的新选择 🗺️

传统的Object和Array已经不能满足所有需求?Map和Set为我们提供了更强大、更灵活的数据结构选择。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 🗺️ Map:键可以是任意类型的键值对集合

// 传统Object的限制
const obj = {};
obj[1] = 'number key'; // 1被转换为字符串'1'
obj[true] = 'boolean key'; // true被转换为字符串'true'
obj[{}] = 'object key'; // {}被转换为字符串'[object Object]'

console.log(Object.keys(obj)); // ['1', 'true', '[object Object]']

// ✨ Map的强大
const map = new Map();

// 任意类型的键
map.set(1, 'number key');
map.set('1', 'string key');
map.set(true, 'boolean key');
map.set({id: 1}, 'object key');
map.set(() => {}, 'function key');

console.log(map.size); // 5,每个键都是独立的

// 🎯 实际应用:缓存系统
class Cache {
constructor(maxSize = 100) {
this.cache = new Map();
this.maxSize = maxSize;
}

get(key) {
if (this.cache.has(key)) {
// LRU策略:访问时移到最后
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
return null;
}

set(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.maxSize) {
// 删除最旧的项(第一个)
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}

this.cache.set(key, value);
}

clear() {
this.cache.clear();
}

// 获取缓存统计
getStats() {
return {
size: this.cache.size,
maxSize: this.maxSize,
keys: Array.from(this.cache.keys())
};
}
}

// 🌐 DOM节点关联数据
const nodeData = new Map();

function attachData(element, data) {
nodeData.set(element, data);
}

function getData(element) {
return nodeData.get(element);
}

// 使用
const button = document.querySelector('#my-button');
attachData(button, {
clickCount: 0,
lastClicked: null,
handler: () => console.log('clicked!')
});

// 📊 统计计数器
class Counter {
constructor() {
this.counts = new Map();
}

increment(key) {
this.counts.set(key, (this.counts.get(key) || 0) + 1);
}

getCount(key) {
return this.counts.get(key) || 0;
}

getTop(n = 10) {
return Array.from(this.counts.entries())
.sort(([,a], [,b]) => b - a)
.slice(0, n);
}

reset() {
this.counts.clear();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// 🎯 Set:自动去重的值集合

// 基础去重
const numbers = [1, 2, 2, 3, 3, 4, 5, 5];
const uniqueNumbers = [...new Set(numbers)]; // [1, 2, 3, 4, 5]

// 字符串去重
const text = "hello world";
const uniqueChars = [...new Set(text)]; // ['h', 'e', 'l', 'o', ' ', 'w', 'r', 'd']

// 🔍 数组操作:交集、并集、差集
function arrayIntersection(arr1, arr2) {
const set1 = new Set(arr1);
return arr2.filter(item => set1.has(item));
}

function arrayUnion(arr1, arr2) {
return [...new Set([...arr1, ...arr2])];
}

function arrayDifference(arr1, arr2) {
const set2 = new Set(arr2);
return arr1.filter(item => !set2.has(item));
}

// 使用示例
const fruits1 = ['apple', 'banana', 'orange'];
const fruits2 = ['banana', 'orange', 'grape'];

console.log(arrayIntersection(fruits1, fruits2)); // ['banana', 'orange']
console.log(arrayUnion(fruits1, fruits2)); // ['apple', 'banana', 'orange', 'grape']
console.log(arrayDifference(fruits1, fruits2)); // ['apple']

// 🎮 游戏开发:标签系统
class TagSystem {
constructor() {
this.entityTags = new Map(); // 实体ID -> Set<标签>
this.tagEntities = new Map(); // 标签 -> Set<实体ID>
}

addTag(entityId, tag) {
// 为实体添加标签
if (!this.entityTags.has(entityId)) {
this.entityTags.set(entityId, new Set());
}
this.entityTags.get(entityId).add(tag);

// 为标签添加实体
if (!this.tagEntities.has(tag)) {
this.tagEntities.set(tag, new Set());
}
this.tagEntities.get(tag).add(entityId);
}

removeTag(entityId, tag) {
this.entityTags.get(entityId)?.delete(tag);
this.tagEntities.get(tag)?.delete(entityId);
}

hasTag(entityId, tag) {
return this.entityTags.get(entityId)?.has(tag) || false;
}

getEntitiesByTag(tag) {
return Array.from(this.tagEntities.get(tag) || []);
}

getEntityTags(entityId) {
return Array.from(this.entityTags.get(entityId) || []);
}

// 查询同时拥有多个标签的实体
getEntitiesWithAllTags(...tags) {
if (tags.length === 0) return [];

let result = this.getEntitiesByTag(tags[0]);

for (let i = 1; i < tags.length; i++) {
const entitiesWithTag = this.getEntitiesByTag(tags[i]);
result = result.filter(id => entitiesWithTag.includes(id));
}

return result;
}
}

// 使用示例
const tagSystem = new TagSystem();

// 添加实体和标签
tagSystem.addTag('player1', 'human');
tagSystem.addTag('player1', 'warrior');
tagSystem.addTag('player1', 'alive');

tagSystem.addTag('enemy1', 'orc');
tagSystem.addTag('enemy1', 'warrior');
tagSystem.addTag('enemy1', 'alive');

// 查询
console.log(tagSystem.getEntitiesByTag('warrior')); // ['player1', 'enemy1']
console.log(tagSystem.getEntitiesWithAllTags('warrior', 'alive')); // ['player1', 'enemy1']

// 🔐 权限系统
class PermissionSystem {
constructor() {
this.userPermissions = new Map(); // 用户ID -> Set<权限>
this.rolePermissions = new Map(); // 角色 -> Set<权限>
this.userRoles = new Map(); // 用户ID -> Set<角色>
}

addPermissionToRole(role, permission) {
if (!this.rolePermissions.has(role)) {
this.rolePermissions.set(role, new Set());
}
this.rolePermissions.get(role).add(permission);
}

assignRoleToUser(userId, role) {
if (!this.userRoles.has(userId)) {
this.userRoles.set(userId, new Set());
}
this.userRoles.get(userId).add(role);
}

getUserPermissions(userId) {
const permissions = new Set();

// 直接权限
const directPermissions = this.userPermissions.get(userId) || new Set();
directPermissions.forEach(p => permissions.add(p));

// 角色权限
const roles = this.userRoles.get(userId) || new Set();
roles.forEach(role => {
const rolePerms = this.rolePermissions.get(role) || new Set();
rolePerms.forEach(p => permissions.add(p));
});

return permissions;
}

hasPermission(userId, permission) {
return this.getUserPermissions(userId).has(permission);
}
}

Map vs Object,Set vs Array

  • 🗺️ Map优势:任意类型键、有序、size属性、更好的迭代性能
  • 📦 Object优势:JSON序列化、属性访问语法、更好的内存效率(小数据)
  • 🎯 Set优势:自动去重、has()方法O(1)复杂度、数学集合操作
  • 📋 Array优势:索引访问、丰富的方法、JSON序列化

🎯 ES6学习路线图与实战建议

学完这么多特性,如何在实际项目中应用?这里给出一个循序渐进的学习路线:

ES6学习路线

基础阶段

掌握核心语法

  • ✅ let/const替代var
  • ✅ 箭头函数基本用法
  • ✅ 模板字符串
  • ✅ 解构赋值
  • ✅ 展开运算符

实践项目:重构一个小型项目,用ES6语法替换ES5写法

进阶阶段

异步编程精通

  • ✅ Promise深入理解
  • ✅ async/await熟练运用
  • ✅ 错误处理最佳实践
  • ✅ 并发控制技巧

实践项目:构建一个数据获取和处理的应用

高级阶段

模块化与架构

  • ✅ ES6模块系统
  • ✅ 动态导入
  • ✅ 模块设计模式
  • ✅ 打包工具配置

实践项目:设计一个可扩展的前端架构

专家阶段

深度特性应用

  • ✅ Map/Set数据结构
  • ✅ Proxy/Reflect元编程
  • ✅ 迭代器与生成器
  • ✅ 性能优化技巧

实践项目:开发一个复杂的业务系统或开源库

🚀 总结:拥抱现代JavaScript

ES6不仅仅是语法的升级,更是编程思维的转变。它让JavaScript从一个”玩具语言”真正成长为企业级开发语言。

🎯 核心收获

  • 语法更简洁:箭头函数、模板字符串、解构赋值让代码更优雅
  • 功能更强大:Promise、模块化、新数据结构解决实际问题
  • 开发更高效:可选链、空值合并减少防御性编程
  • 架构更清晰:模块化让大型项目组织更合理

💡 实践建议

  1. 循序渐进:从基础语法开始,逐步掌握高级特性
  2. 项目驱动:在实际项目中应用,加深理解
  3. 持续学习:JavaScript生态快速发展,保持学习热情
  4. 分享交流:与同行交流经验,共同进步

⚠️ 注意事项

  • 浏览器兼容性:考虑目标用户的浏览器支持情况
  • 打包工具:使用Babel等工具确保兼容性
  • 性能考量:新特性虽好,但要考虑性能影响
  • 团队规范:制定团队编码规范,保持代码一致性

现代JavaScript的世界精彩纷呈,ES6只是一个开始。继续探索ES2017、ES2018…的新特性,让我们的代码更加现代化!

Happy Coding! 🎉