Search K
Appearance
Appearance
📊 SEO元描述:2024年最新JavaScript代理模式教程,详解Proxy代理原理、虚拟代理实现、缓存代理应用。包含完整代码示例,适合前端开发者快速掌握设计模式。
核心关键词:JavaScript代理模式2024、Proxy代理模式、JavaScript Proxy、虚拟代理、缓存代理
长尾关键词:代理模式怎么实现、JavaScript Proxy用法、代理模式应用场景、虚拟代理原理、JavaScript高级编程
通过本节JavaScript代理模式完整教程,你将系统性掌握:
代理模式是什么?这是前端开发者在学习高级JavaScript特性时最常问的问题。代理模式是一种结构型设计模式,它为另一个对象提供一个替身或占位符以控制对这个对象的访问,也是访问控制和性能优化的重要组成部分。
💡 设计模式建议:代理模式特别适合需要控制访问、延迟加载、缓存优化的场景,如图片懒加载、API请求缓存、权限验证等。
ES6的Proxy对象为JavaScript提供了强大的代理功能:
// 🎉 基础Proxy使用示例
const target = {
name: 'JavaScript',
version: 'ES2024',
features: ['Proxy', 'Reflect', 'Async/Await']
};
const handler = {
// 拦截属性读取
get(target, property, receiver) {
console.log(`访问属性: ${property}`);
if (property in target) {
return Reflect.get(target, property, receiver);
} else {
console.log(`属性 ${property} 不存在`);
return undefined;
}
},
// 拦截属性设置
set(target, property, value, receiver) {
console.log(`设置属性: ${property} = ${value}`);
// 数据验证
if (property === 'version' && typeof value !== 'string') {
throw new TypeError('Version must be a string');
}
return Reflect.set(target, property, value, receiver);
},
// 拦截属性删除
deleteProperty(target, property) {
console.log(`删除属性: ${property}`);
if (property === 'name') {
console.log('不能删除name属性');
return false;
}
return Reflect.deleteProperty(target, property);
},
// 拦截属性枚举
ownKeys(target) {
console.log('枚举对象属性');
return Reflect.ownKeys(target);
}
};
const proxy = new Proxy(target, handler);
// 使用代理对象
console.log(proxy.name); // 访问属性: name
proxy.author = 'Developer'; // 设置属性: author = Developer
delete proxy.version; // 删除属性: version
Object.keys(proxy); // 枚举对象属性虚拟代理通过延迟创建和加载资源来优化性能:
// 🎉 图片虚拟代理实现
class ImageProxy {
constructor(src) {
this.src = src;
this.image = null;
this.loading = false;
this.loaded = false;
this.observers = [];
}
// 添加加载完成观察者
onLoad(callback) {
if (this.loaded) {
callback(this.image);
} else {
this.observers.push(callback);
}
}
// 延迟加载图片
load() {
if (this.loading || this.loaded) {
return Promise.resolve(this.image);
}
this.loading = true;
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
this.image = img;
this.loaded = true;
this.loading = false;
// 通知所有观察者
this.observers.forEach(callback => callback(img));
this.observers = [];
resolve(img);
};
img.onerror = (error) => {
this.loading = false;
reject(error);
};
img.src = this.src;
});
}
// 获取图片尺寸(虚拟代理方法)
getDimensions() {
if (this.loaded) {
return {
width: this.image.naturalWidth,
height: this.image.naturalHeight
};
}
return { width: 0, height: 0 };
}
}
// 🎉 图片管理器
class ImageManager {
constructor() {
this.images = new Map();
}
getImage(src) {
if (!this.images.has(src)) {
this.images.set(src, new ImageProxy(src));
}
return this.images.get(src);
}
preloadImages(srcList) {
return Promise.all(
srcList.map(src => this.getImage(src).load())
);
}
}
// 使用示例
const imageManager = new ImageManager();
const image1 = imageManager.getImage('/images/large-photo.jpg');
// 图片还未加载,但可以设置回调
image1.onLoad((img) => {
console.log('图片加载完成:', img.src);
document.body.appendChild(img);
});
// 触发加载
image1.load();// 🎉 API请求缓存代理
class APICache {
constructor(ttl = 300000) { // 默认5分钟过期
this.cache = new Map();
this.ttl = ttl;
}
set(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now()
});
}
get(key) {
const item = this.cache.get(key);
if (!item) {
return null;
}
// 检查是否过期
if (Date.now() - item.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return item.data;
}
clear() {
this.cache.clear();
}
size() {
return this.cache.size;
}
}
// 🎉 HTTP请求缓存代理
class CachedHTTPClient {
constructor(httpClient, cacheOptions = {}) {
this.httpClient = httpClient;
this.cache = new APICache(cacheOptions.ttl);
this.cacheableMethod = cacheOptions.methods || ['GET'];
}
async request(config) {
const { method = 'GET', url, params } = config;
// 只缓存指定的HTTP方法
if (this.cacheableMethod.includes(method.toUpperCase())) {
const cacheKey = this.generateCacheKey(method, url, params);
const cachedData = this.cache.get(cacheKey);
if (cachedData) {
console.log(`缓存命中: ${cacheKey}`);
return Promise.resolve(cachedData);
}
try {
const response = await this.httpClient.request(config);
this.cache.set(cacheKey, response);
console.log(`缓存存储: ${cacheKey}`);
return response;
} catch (error) {
throw error;
}
}
// 非缓存请求直接执行
return this.httpClient.request(config);
}
generateCacheKey(method, url, params) {
const paramString = params ? JSON.stringify(params) : '';
return `${method}:${url}:${paramString}`;
}
// 代理其他HTTP方法
get(url, config = {}) {
return this.request({ ...config, method: 'GET', url });
}
post(url, data, config = {}) {
return this.request({ ...config, method: 'POST', url, data });
}
// 缓存管理方法
clearCache() {
this.cache.clear();
}
getCacheStats() {
return {
size: this.cache.size(),
ttl: this.cache.ttl
};
}
}
// 使用示例
const httpClient = {
async request(config) {
// 模拟HTTP请求
console.log(`发送请求: ${config.method} ${config.url}`);
return { data: `Response for ${config.url}`, status: 200 };
}
};
const cachedClient = new CachedHTTPClient(httpClient, {
ttl: 60000, // 1分钟缓存
methods: ['GET', 'POST']
});
// 第一次请求 - 发送真实请求
cachedClient.get('/api/users').then(response => {
console.log('第一次请求:', response);
});
// 第二次请求 - 使用缓存
setTimeout(() => {
cachedClient.get('/api/users').then(response => {
console.log('第二次请求:', response);
});
}, 1000);// 🎉 权限控制代理
class PermissionProxy {
constructor(target, permissions) {
this.target = target;
this.permissions = permissions;
return new Proxy(target, {
get: (target, property) => {
if (this.hasPermission(property, 'read')) {
return Reflect.get(target, property);
} else {
throw new Error(`没有读取 ${property} 的权限`);
}
},
set: (target, property, value) => {
if (this.hasPermission(property, 'write')) {
return Reflect.set(target, property, value);
} else {
throw new Error(`没有写入 ${property} 的权限`);
}
},
deleteProperty: (target, property) => {
if (this.hasPermission(property, 'delete')) {
return Reflect.deleteProperty(target, property);
} else {
throw new Error(`没有删除 ${property} 的权限`);
}
}
});
}
hasPermission(property, action) {
const permission = this.permissions[property];
return permission && permission.includes(action);
}
}
// 使用示例
const sensitiveData = {
publicInfo: '公开信息',
privateInfo: '私密信息',
adminInfo: '管理员信息'
};
const userPermissions = {
publicInfo: ['read'],
privateInfo: ['read', 'write'],
adminInfo: [] // 无权限
};
const protectedData = new PermissionProxy(sensitiveData, userPermissions);
console.log(protectedData.publicInfo); // 正常访问
protectedData.privateInfo = '更新的私密信息'; // 正常写入
// console.log(protectedData.adminInfo); // 抛出权限错误代理模式的应用场景:
💼 实际应用数据:使用代理模式可以减少60%的重复请求,提升50%的页面加载速度,同时增强系统的安全性和可控性。
通过本节JavaScript代理模式完整教程的学习,你已经掌握:
A: Proxy可以拦截更多操作(13种),支持数组索引,性能更好;Object.defineProperty只能拦截属性的get/set,不支持数组索引,但兼容性更好。
A: Proxy本身有轻微性能开销,但通过缓存、懒加载等优化,通常能带来整体性能提升。在性能敏感场景中需要谨慎使用。
A: 可以在handler方法中添加console.log,或使用浏览器的断点调试。注意Proxy可能会影响某些调试工具的表现。
A: 代理模式控制访问,可能不创建目标对象;装饰器模式增强功能,目标对象始终存在。代理更注重控制,装饰器更注重增强。
A: 当需要兼容旧浏览器、性能要求极高、或者简单的属性访问控制时,可以考虑使用其他方案如Object.defineProperty。
// 问题:Proxy操作频繁导致性能问题
// 解决:添加操作缓存和批量处理
class OptimizedProxy {
constructor(target) {
this.target = target;
this.operationCache = new Map();
return new Proxy(target, {
get: (target, property) => {
const cacheKey = `get_${property}`;
if (this.operationCache.has(cacheKey)) {
return this.operationCache.get(cacheKey);
}
const result = Reflect.get(target, property);
this.operationCache.set(cacheKey, result);
return result;
}
});
}
}// 问题:Proxy对象难以调试
// 解决:添加调试模式和日志记录
function createDebuggableProxy(target, debug = false) {
return new Proxy(target, {
get(target, property, receiver) {
if (debug) {
console.log(`[DEBUG] 访问属性: ${property}`);
}
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
if (debug) {
console.log(`[DEBUG] 设置属性: ${property} = ${value}`);
}
return Reflect.set(target, property, value, receiver);
}
});
}"掌握代理模式,让你的JavaScript应用更加智能和安全。通过Proxy的强大功能,实现高效的访问控制和性能优化!"