现代JavaScript框架中的设计模式实践
模块化与组件化设计
现代JavaScript框架如React、Vue和Angular都采用了模块化和组件化的设计思想。这种模式将UI拆分为独立、可复用的组件,每个组件管理自己的状态和行为。组件化设计遵循单一职责原则,使得代码更易于维护和测试。
// React函数组件示例
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
在Vue中,单文件组件(SFC)将模板、逻辑和样式封装在一个文件中:
<!-- Vue单文件组件示例 -->
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
this.count++
}
}
}
</script>
状态管理模式
随着应用复杂度增加,状态管理成为关键挑战。Redux和Vuex等库实现了Flux架构,采用单一数据源和单向数据流原则。这种模式确保状态变更可预测且易于追踪。
// Redux状态管理示例
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
}
const store = createStore(counterReducer);
现代框架也引入了更轻量的状态管理方案,如React的Context API:
// React Context示例
const CountContext = createContext();
function App() {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
<ChildComponent />
</CountContext.Provider>
);
}
function ChildComponent() {
const { count, setCount } = useContext(CountContext);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
观察者模式与响应式系统
Vue的核心是响应式系统,基于观察者模式实现。当数据变化时,依赖该数据的视图会自动更新。这种模式通过Object.defineProperty或Proxy实现数据劫持。
// Vue响应式原理简化实现
function defineReactive(obj, key, val) {
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend(); // 收集依赖
return val;
},
set(newVal) {
val = newVal;
dep.notify(); // 通知更新
}
});
}
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
React的Hooks也采用了类似的观察机制,useEffect可以订阅状态变化:
// React useEffect示例
function Example({ someProp }) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]); // 只在count变化时执行
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
高阶组件与渲染属性
高阶组件(HOC)是React中复用组件逻辑的高级技术。这种模式本质上是函数式编程中的高阶函数概念在组件层面的应用。
// React高阶组件示例
function withLoading(WrappedComponent) {
return function WithLoading({ isLoading, ...props }) {
return isLoading ? <div>Loading...</div> : <WrappedComponent {...props} />;
};
}
const EnhancedComponent = withLoading(MyComponent);
渲染属性(Render Props)是另一种共享代码的方式,通过prop传递渲染函数:
// Render Props示例
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// 使用
<MouseTracker render={({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
)} />
依赖注入与控制反转
Angular框架大量使用依赖注入(DI)模式,通过装饰器声明依赖关系,框架负责实例化和注入。
// Angular服务与依赖注入示例
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) {}
getData() {
return this.http.get('/api/data');
}
}
@Component({
selector: 'app-example',
templateUrl: './example.component.html'
})
export class ExampleComponent {
constructor(private dataService: DataService) {}
loadData() {
this.dataService.getData().subscribe(data => {
// 处理数据
});
}
}
React的Context API也可以视为一种轻量级的依赖注入实现:
// React Context作为DI容器
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
策略模式与组合模式
策略模式在表单验证等场景中非常有用,可以动态切换算法或行为:
// 表单验证策略模式
const validationStrategies = {
required: (value) => !!value || '必填字段',
email: (value) => /.+@.+\..+/.test(value) || '无效邮箱',
minLength: (length) => (value) =>
value.length >= length || `至少${length}个字符`
};
function validate(formData, rules) {
return Object.entries(rules).reduce((errors, [field, fieldRules]) => {
fieldRules.forEach(({ strategy, params }) => {
const validator = typeof strategy === 'function'
? strategy
: validationStrategies[strategy];
const error = validator(formData[field], ...(params || []));
if (error) errors[field] = error;
});
return errors;
}, {});
}
组合模式在UI树形结构中很常见,React组件本身就是组合模式的体现:
// React组合组件示例
function Card({ children }) {
return <div className="card">{children}</div>;
}
function CardHeader({ title }) {
return <div className="card-header">{title}</div>;
}
function CardBody({ content }) {
return <div className="card-body">{content}</div>;
}
// 使用组合
<Card>
<CardHeader title="示例卡片" />
<CardBody content="这是卡片内容..." />
</Card>
代理模式与备忘录模式
Proxy在现代JavaScript中非常强大,Vue3使用它实现响应式系统:
// Proxy实现响应式
function reactive(target) {
const handler = {
get(target, key, receiver) {
track(target, key);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key);
return true;
}
};
return new Proxy(target, handler);
}
function track(target, key) {
// 收集依赖
}
function trigger(target, key) {
// 触发更新
}
备忘录模式在状态管理中很常见,如实现撤销/重做功能:
// 简易备忘录模式实现
class EditorHistory {
constructor() {
this.states = [];
this.current = -1;
}
pushState(state) {
this.states = this.states.slice(0, this.current + 1);
this.states.push(JSON.parse(JSON.stringify(state)));
this.current = this.states.length - 1;
}
undo() {
if (this.current <= 0) return null;
this.current--;
return this.states[this.current];
}
redo() {
if (this.current >= this.states.length - 1) return null;
this.current++;
return this.states[this.current];
}
}
工厂模式与单例模式
工厂模式在创建复杂对象时很有用,特别是需要根据不同条件创建不同类型对象时:
// 组件工厂示例
function createComponent(type, props) {
switch (type) {
case 'button':
return new ButtonComponent(props);
case 'input':
return new InputComponent(props);
case 'select':
return new SelectComponent(props);
default:
throw new Error(`Unknown component type: ${type}`);
}
}
class ButtonComponent {
constructor(props) {
this.props = props;
}
render() {
return `<button class="${this.props.className}">${this.props.label}</button>`;
}
}
单例模式确保一个类只有一个实例,Redux store就是典型例子:
// Redux store单例
let storeInstance = null;
function configureStore(preloadedState) {
if (storeInstance) {
return storeInstance;
}
storeInstance = createStore(
rootReducer,
preloadedState,
applyMiddleware(thunk, logger)
);
return storeInstance;
}
适配器模式与外观模式
适配器模式在不兼容接口之间建立桥梁,常见于API封装:
// API适配器示例
class OldApi {
request(data, callback) {
// 旧式回调API
setTimeout(() => callback(data), 1000);
}
}
class ApiAdapter {
constructor(oldApi) {
this.oldApi = oldApi;
}
async fetch(data) {
return new Promise((resolve) => {
this.oldApi.request(data, resolve);
});
}
}
// 使用
const adapter = new ApiAdapter(new OldApi());
const result = await adapter.fetch({ id: 1 });
外观模式为复杂子系统提供简化接口,如Axios封装HTTP请求:
// HTTP客户端外观
const http = {
get(url, config) {
return axios.get(url, config);
},
post(url, data, config) {
return axios.post(url, data, config);
},
put(url, data, config) {
return axios.put(url, data, config);
},
delete(url, config) {
return axios.delete(url, config);
}
};
// 使用简化接口
http.get('/api/users')
.then(response => console.log(response.data));
中间件模式与插件系统
中间件模式允许在不修改核心代码的情况下扩展功能,常见于Express、Redux等库:
// Redux中间件机制
const loggerMiddleware = store => next => action => {
console.log('dispatching', action);
let result = next(action);
console.log('next state', store.getState());
return result;
};
const thunkMiddleware = store => next => action => {
if (typeof action === 'function') {
return action(store.dispatch, store.getState);
}
return next(action);
};
const store = createStore(
rootReducer,
applyMiddleware(loggerMiddleware, thunkMiddleware)
);
插件系统允许第三方扩展框架功能,如Vue插件:
// Vue插件示例
const MyPlugin = {
install(Vue, options) {
// 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
};
// 添加全局指令
Vue.directive('my-directive', {
bind(el, binding, vnode, oldVnode) {
// 逻辑...
}
});
// 注入组件选项
Vue.mixin({
created() {
// 逻辑...
}
});
// 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
};
}
};
// 使用插件
Vue.use(MyPlugin, { someOption: true });
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:设计模式的优缺点分析
下一篇:设计模式的学习路径与资源推荐