JavaScript设计模式与安全实践指南
JavaScript 设计模式与安全实践指南
一、设计模式在 JavaScript 中的应用
1. 工厂模式:灵活的对象创建
工厂模式通过将对象创建逻辑封装在函数中,提供了一种创建对象的统一接口。
class Car {
constructor(model, year) {
this.model = model;
this.year = year;
}
}
class Truck {
constructor(model, year) {
this.model = model;
this.year = year;
}
}
function vehicleFactory(type, model, year) {
switch(type) {
case 'car':
return new Car(model, year);
case 'truck':
return new Truck(model, year);
default:
throw new Error('Unknown vehicle type');
}
}
const myCar = vehicleFactory('car', 'Tesla', 2023);
const myTruck = vehicleFactory('truck', 'Ford', 2022);
实践建议:
- 当对象创建逻辑复杂时使用工厂模式
- 适用于需要根据不同条件创建不同对象的场景
- 有利于代码解耦,符合单一职责原则
2. 单例模式:全局唯一实例
单例模式确保一个类只有一个实例,并提供全局访问点。
class DatabaseConnection {
constructor() {
if (DatabaseConnection.instance) {
return DatabaseConnection.instance;
}
this.connection = this.createConnection();
DatabaseConnection.instance = this;
return this;
}
createConnection() {
// 模拟数据库连接
console.log('Creating new database connection...');
return { status: 'connected' };
}
}
const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();
console.log(db1 === db2); // true
实践建议:
- 适用于数据库连接、日志记录器等需要全局唯一实例的场景
- 注意线程安全问题(在JavaScript中通常不是问题)
- 考虑使用模块系统(如ES Modules)实现更简单的单例
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 {
update(data) {
console.log(`Received data: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify('Hello World!');
// 输出:
// Received data: Hello World!
// Received data: Hello World!
实践建议:
- 适用于需要实现松耦合的事件处理系统
- 现代前端框架(如React、Vue)的状态管理库(Redux、Vuex)都基于此模式
- 注意及时取消订阅避免内存泄漏
二、JavaScript 安全实践
1. XSS 防御:保护你的应用
跨站脚本攻击(XSS)是JavaScript应用最常见的安全威胁之一。
防御措施:
// 1. 转义HTML内容
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// 2. 使用textContent而不是innerHTML
element.textContent = userInput;
// 3. 现代框架的内置防护
// React/Vue/Angular等框架默认会转义动态内容
实践建议:
- 始终对用户输入进行验证和转义
- 使用Content Security Policy (CSP)作为额外防护层
- 避免使用
eval()
和innerHTML
等危险API
2. CSRF 防护:阻止跨站请求伪造
// 1. 使用CSRF令牌
// 后端生成令牌并包含在表单中
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="token-value">
<!-- 其他表单字段 -->
</form>
// 2. 设置SameSite Cookie属性
// 服务器设置Cookie时
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure
// 3. 验证请求来源
app.use((req, res, next) => {
const allowedOrigins = ['https://yourdomain.com'];
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
next();
});
实践建议:
- 结合多种防护措施(令牌+SameSite+来源验证)
- 对于敏感操作考虑增加二次验证
- 定期审计API端点安全性
3. Content Security Policy (CSP) 配置
CSP通过白名单机制限制资源加载,有效防御XSS攻击。
<!-- 示例CSP策略 -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' https://apis.google.com;
img-src 'self' https://*.example.com;
style-src 'self' 'unsafe-inline';
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';">
实践建议:
- 从严格策略开始,逐步放宽必要规则
- 使用
report-uri
收集违规报告 - 在生产环境前充分测试所有功能
三、现代工具链配置技巧
1. Webpack 优化配置
// webpack.config.js
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].[contenthash].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
optimization: {
splitChunks: {
chunks: 'all',
},
runtimeChunk: 'single',
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
实践建议:
- 使用代码分割提升加载性能
- 长期缓存利用contenthash
- 开发环境启用HMR(热模块替换)
2. Babel 转译配置
// .babelrc
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["last 2 versions", "not dead"]
},
"useBuiltIns": "usage",
"corejs": 3
}]
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime"
]
}
实践建议:
- 根据目标浏览器配置preset-env
- 使用core-js自动polyfill
- 开发库时使用transform-runtime避免全局污染
3. ESLint 代码规范
// .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'airbnb',
'prettier',
],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
},
plugins: ['react', 'prettier'],
rules: {
'prettier/prettier': 'error',
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'import/prefer-default-export': 'off',
'no-param-reassign': ['error', { props: false }],
},
};
实践建议:
- 结合Prettier统一代码风格
- 根据团队习惯定制规则
- 在CI/CD流程中加入lint检查
四、框架特性深度解析
1. React Hooks 高级用法
import { useState, useEffect, useMemo, useCallback } from 'react';
function UserList({ users }) {
const [searchTerm, setSearchTerm] = useState('');
const [filteredUsers, setFilteredUsers] = useState([]);
// 使用useMemo优化计算
const sortedUsers = useMemo(() => {
return [...users].sort((a, b) => a.name.localeCompare(b.name));
}, [users]);
// 使用useCallback记忆函数
const handleSearch = useCallback((term) => {
const filtered = sortedUsers.filter(user =>
user.name.toLowerCase().includes(term.toLowerCase())
);
setFilteredUsers(filtered);
}, [sortedUsers]);
// 副作用处理
useEffect(() => {
handleSearch(searchTerm);
}, [searchTerm, handleSearch]);
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<ul>
{filteredUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
实践建议:
- 使用useMemo缓存昂贵计算
- 使用useCallback避免不必要的重新渲染
- 按逻辑拆分自定义Hook提高可复用性
2. Vue 响应式原理剖析
Vue 3使用Proxy实现响应式系统:
const reactive = (target) => {
return new Proxy(target, {
get(obj, key) {
track(obj, key); // 依赖收集
return Reflect.get(obj, key);
},
set(obj, key, value) {
Reflect.set(obj, key, value);
trigger(obj, key); // 触发更新
return true;
},
});
};
function track(target, key) {
// 记录当前正在运行的effect
if (activeEffect) {
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const effects = depsMap.get(key);
effects && effects.forEach(effect => effect());
}
实践建议:
- 理解响应式原理有助于性能优化
- 避免在大型数据结构上使用响应式
- 使用shallowRef/shallowReactive减少不必要的响应式开销
总结
JavaScript生态系统不断发展,掌握核心设计模式和安全实践是成为高级开发者的关键。通过:
- 合理应用设计模式提高代码质量
- 严格实施安全防护措施
- 熟练使用现代工具链提升开发效率
- 深入理解框架特性实现最佳实践
可以构建出更健壮、更安全的JavaScript应用。记住,良好的架构和安全意识应该从项目开始就纳入考虑,而不是事后补救。
评论已关闭