创建型与结构型模式
单例模式
js
// 前端最常见的单例:Vuex Store
class Store {
constructor() {
if (Store.instance) return Store.instance
this.state = {}
Store.instance = this
}
}
// 使用:const store = new Store() // 全局唯一
// 弹窗管理器
class ModalManager {
static #instance
constructor() {
if (ModalManager.#instance) return ModalManager.#instance
this.modals = new Map()
ModalManager.#instance = this
}
show(name, config) { /* ... */ }
hide(name) { /* ... */ }
}
// 模块化方式(推荐)
// store.js
export const store = {
state: new Map(),
set(key, val) { this.state.set(key, val) },
get(key) { return this.state.get(key) },
}// 前端最常见的单例:Vuex Store
class Store {
constructor() {
if (Store.instance) return Store.instance
this.state = {}
Store.instance = this
}
}
// 使用:const store = new Store() // 全局唯一
// 弹窗管理器
class ModalManager {
static #instance
constructor() {
if (ModalManager.#instance) return ModalManager.#instance
this.modals = new Map()
ModalManager.#instance = this
}
show(name, config) { /* ... */ }
hide(name) { /* ... */ }
}
// 模块化方式(推荐)
// store.js
export const store = {
state: new Map(),
set(key, val) { this.state.set(key, val) },
get(key) { return this.state.get(key) },
}工厂模式
js
// 创建不同 UI 组件
class ButtonFactory {
createButton(type) {
switch (type) {
case 'primary':
return new PrimaryButton()
case 'secondary':
return new SecondaryButton()
case 'danger':
return new DangerButton()
default:
throw new Error('Unknown button type')
}
}
}
// React 中简单工厂
function createButton(config) {
const { type, text, onClick } = config
const baseClass = 'btn'
switch (type) {
case 'primary':
return <button className={`${baseClass} btn-primary`} onClick={onClick}>{text}</button>
case 'icon':
return <button className={`${baseClass} btn-icon`} onClick={onClick}><Icon name={text} /></button>
default:
return <button className={baseClass} onClick={onClick}>{text}</button>
}
}
// axios 实例工厂
function createApiClient(baseURL) {
const instance = axios.create({ baseURL })
instance.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`
return config
})
instance.interceptors.response.use(
res => res.data,
err => handleError(err)
)
return instance
}
export const api = createApiClient(import.meta.env.VITE_API_URL)
export const authApi = createApiClient(import.meta.env.VITE_AUTH_URL)// 创建不同 UI 组件
class ButtonFactory {
createButton(type) {
switch (type) {
case 'primary':
return new PrimaryButton()
case 'secondary':
return new SecondaryButton()
case 'danger':
return new DangerButton()
default:
throw new Error('Unknown button type')
}
}
}
// React 中简单工厂
function createButton(config) {
const { type, text, onClick } = config
const baseClass = 'btn'
switch (type) {
case 'primary':
return <button className={`${baseClass} btn-primary`} onClick={onClick}>{text}</button>
case 'icon':
return <button className={`${baseClass} btn-icon`} onClick={onClick}><Icon name={text} /></button>
default:
return <button className={baseClass} onClick={onClick}>{text}</button>
}
}
// axios 实例工厂
function createApiClient(baseURL) {
const instance = axios.create({ baseURL })
instance.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`
return config
})
instance.interceptors.response.use(
res => res.data,
err => handleError(err)
)
return instance
}
export const api = createApiClient(import.meta.env.VITE_API_URL)
export const authApi = createApiClient(import.meta.env.VITE_AUTH_URL)代理模式
js
// Vue 3 响应式系统核心
const reactive = (obj) => {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key) // 依赖收集
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
trigger(target, key) // 触发更新
}
return result
},
})
}
// 图片懒加载
const lazyImage = new Proxy(Image, {
construct(target, args) {
const img = new target(...args)
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
img.src = img.dataset.src
observer.disconnect()
}
})
observer.observe(img)
return img
},
})// Vue 3 响应式系统核心
const reactive = (obj) => {
return new Proxy(obj, {
get(target, key, receiver) {
track(target, key) // 依赖收集
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
trigger(target, key) // 触发更新
}
return result
},
})
}
// 图片懒加载
const lazyImage = new Proxy(Image, {
construct(target, args) {
const img = new target(...args)
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) {
img.src = img.dataset.src
observer.disconnect()
}
})
observer.observe(img)
return img
},
})装饰器模式
js
// 高阶组件 (HOC)
function withLogger(Component) {
return function Enhanced(props) {
useEffect(() => {
console.log(`${Component.name} mounted`)
return () => console.log(`${Component.name} unmounted`)
}, [])
return <Component {...props} />
}
}
// TypeScript 装饰器
function log(target, key, descriptor) {
const original = descriptor.value
descriptor.value = function (...args) {
console.log(`[${key}] called with`, args)
const result = original.apply(this, args)
console.log(`[${key}] returned`, result)
return result
}
return descriptor
}
class Calculator {
@log
add(a, b) { return a + b }
}
// React Hooks 也是装饰器思想的体现
function useLoading(fn) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const execute = async (...args) => {
setLoading(true)
setError(null)
try {
return await fn(...args)
} catch (e) {
setError(e)
} finally {
setLoading(false)
}
}
return { execute, loading, error }
}// 高阶组件 (HOC)
function withLogger(Component) {
return function Enhanced(props) {
useEffect(() => {
console.log(`${Component.name} mounted`)
return () => console.log(`${Component.name} unmounted`)
}, [])
return <Component {...props} />
}
}
// TypeScript 装饰器
function log(target, key, descriptor) {
const original = descriptor.value
descriptor.value = function (...args) {
console.log(`[${key}] called with`, args)
const result = original.apply(this, args)
console.log(`[${key}] returned`, result)
return result
}
return descriptor
}
class Calculator {
@log
add(a, b) { return a + b }
}
// React Hooks 也是装饰器思想的体现
function useLoading(fn) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const execute = async (...args) => {
setLoading(true)
setError(null)
try {
return await fn(...args)
} catch (e) {
setError(e)
} finally {
setLoading(false)
}
}
return { execute, loading, error }
}组合模式
js
// 组件树天然就是组合模式
// 文件:TreeNode.jsx
function TreeNode({ node }) {
return (
<div>
<span>{node.name}</span>
{node.children && (
<div style={{ paddingLeft: 20 }}>
{node.children.map(child => (
<TreeNode key={child.id} node={child} />
))}
</div>
)}
</div>
)
}// 组件树天然就是组合模式
// 文件:TreeNode.jsx
function TreeNode({ node }) {
return (
<div>
<span>{node.name}</span>
{node.children && (
<div style={{ paddingLeft: 20 }}>
{node.children.map(child => (
<TreeNode key={child.id} node={child} />
))}
</div>
)}
</div>
)
}适配器模式
js
// 数据格式适配
class OldApiAdapter {
static adapt(user) {
return {
fullName: `${user.first_name} ${user.last_name}`,
email: user.email_address,
age: new Date().getFullYear() - new Date(user.birth_date).getFullYear(),
avatar: user.profile_pic_url,
}
}
}
// 浏览器 API 适配
class StorageAdapter {
constructor(type = 'local') {
this.storage = type === 'local' ? localStorage : sessionStorage
}
get(key) {
try {
return JSON.parse(this.storage.getItem(key))
} catch {
return this.storage.getItem(key)
}
}
set(key, value) {
this.storage.setItem(key, JSON.stringify(value))
}
remove(key) {
this.storage.removeItem(key)
}
}// 数据格式适配
class OldApiAdapter {
static adapt(user) {
return {
fullName: `${user.first_name} ${user.last_name}`,
email: user.email_address,
age: new Date().getFullYear() - new Date(user.birth_date).getFullYear(),
avatar: user.profile_pic_url,
}
}
}
// 浏览器 API 适配
class StorageAdapter {
constructor(type = 'local') {
this.storage = type === 'local' ? localStorage : sessionStorage
}
get(key) {
try {
return JSON.parse(this.storage.getItem(key))
} catch {
return this.storage.getItem(key)
}
}
set(key, value) {
this.storage.setItem(key, JSON.stringify(value))
}
remove(key) {
this.storage.removeItem(key)
}
}
Cao Note