JavaScript系列(75)--代理模式专题

news/2025/2/20 14:07:21

JavaScript代理模式专题 🎭

JavaScript的Proxy提供了强大的对象代理能力,能够拦截和自定义对象的基本操作。本文将深入探讨Proxy的各种模式、应用场景和最佳实践。

代理基础 🌟

💡 小知识:代理模式允许我们创建一个对象的代理,从而可以控制对这个对象的访问。JavaScript的Proxy API提供了13种基本操作的拦截器(trap),使我们能够自定义对象的行为。

javascript">// 基础代理操作
const target = { name: '张三', age: 25 };
const handler = {
    get(target, property) {
        console.log(`访问属性: ${property}`);
        return target[property];
    },
    set(target, property, value) {
        console.log(`设置属性: ${property} = ${value}`);
        target[property] = value;
        return true;
    }
};

const proxy = new Proxy(target, handler);
console.log(proxy.name);  // 输出: 访问属性: name 然后是 "张三"
proxy.age = 26;          // 输出: 设置属性: age = 26

Proxy拦截器详解 📋

1. 基本拦截器

javascript">class BasicTraps {
    static demonstrateBasicTraps() {
        const handler = {
            // 属性读取拦截
            get(target, prop, receiver) {
                return Reflect.get(target, prop, receiver);
            },
            
            // 属性设置拦截
            set(target, prop, value, receiver) {
                return Reflect.set(target, prop, value, receiver);
            },
            
            // 属性删除拦截
            deleteProperty(target, prop) {
                return Reflect.deleteProperty(target, prop);
            },
            
            // 属性存在性检查拦截
            has(target, prop) {
                return Reflect.has(target, prop);
            }
        };
        
        return new Proxy({}, handler);
    }
}

2. 高级拦截器

javascript">class AdvancedTraps {
    static demonstrateAdvancedTraps() {
        const handler = {
            // 对象属性枚举拦截
            ownKeys(target) {
                return Reflect.ownKeys(target);
            },
            
            // 属性描述符获取拦截
            getOwnPropertyDescriptor(target, prop) {
                return Reflect.getOwnPropertyDescriptor(target, prop);
            },
            
            // 原型获取拦截
            getPrototypeOf(target) {
                return Reflect.getPrototypeOf(target);
            },
            
            // 原型设置拦截
            setPrototypeOf(target, proto) {
                return Reflect.setPrototypeOf(target, proto);
            }
        };
        
        return new Proxy({}, handler);
    }
}

3. 函数和构造器拦截

javascript">class FunctionTraps {
    static demonstrateFunctionTraps() {
        function target(a, b) {
            return a + b;
        }
        
        const handler = {
            // 函数调用拦截
            apply(target, thisArg, args) {
                console.log(`调用函数,参数:${args}`);
                return Reflect.apply(target, thisArg, args);
            },
            
            // 构造函数调用拦截
            construct(target, args, newTarget) {
                console.log(`构造函数调用,参数:${args}`);
                return Reflect.construct(target, args, newTarget);
            }
        };
        
        return new Proxy(target, handler);
    }
}

常用代理模式 💼

1. 验证代理

javascript">class ValidationProxy {
    static createValidator(validationRules) {
        return new Proxy({}, {
            set(target, property, value) {
                if (validationRules[property]) {
                    const [isValid, message] = validationRules[property](value);
                    if (!isValid) {
                        throw new Error(`验证失败: ${property} - ${message}`);
                    }
                }
                return Reflect.set(target, property, value);
            }
        });
    }
}

// 使用示例
const userValidator = ValidationProxy.createValidator({
    age: (value) => [
        Number.isInteger(value) && value >= 0 && value <= 150,
        '年龄必须是0-150之间的整数'
    ],
    email: (value) => [
        /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
        '邮箱格式不正确'
    ]
});

2. 日志代理

javascript">class LoggingProxy {
    static createLogger(target, logCallback = console.log) {
        return new Proxy(target, {
            get(target, property) {
                logCallback(`获取属性: ${property}`);
                return Reflect.get(target, property);
            },
            
            set(target, property, value) {
                logCallback(`设置属性: ${property} = ${value}`);
                return Reflect.set(target, property, value);
            },
            
            deleteProperty(target, property) {
                logCallback(`删除属性: ${property}`);
                return Reflect.deleteProperty(target, property);
            }
        });
    }
}

// 使用示例
const user = LoggingProxy.createLogger({
    name: '张三',
    age: 25
});

3. 访问控制代理

javascript">class AccessControlProxy {
    static createPrivateProperties(target, privateProps = []) {
        return new Proxy(target, {
            get(target, property) {
                if (privateProps.includes(property)) {
                    throw new Error(`无法访问私有属性: ${property}`);
                }
                return Reflect.get(target, property);
            },
            
            set(target, property, value) {
                if (privateProps.includes(property)) {
                    throw new Error(`无法修改私有属性: ${property}`);
                }
                return Reflect.set(target, property, value);
            },
            
            deleteProperty(target, property) {
                if (privateProps.includes(property)) {
                    throw new Error(`无法删除私有属性: ${property}`);
                }
                return Reflect.deleteProperty(target, property);
            }
        });
    }
}

4. 缓存代理

javascript">class CachingProxy {
    static createCached(target, ttl = 5000) {
        const cache = new Map();
        
        return new Proxy(target, {
            apply(target, thisArg, args) {
                const key = JSON.stringify(args);
                const now = Date.now();
                
                if (cache.has(key)) {
                    const [result, timestamp] = cache.get(key);
                    if (now - timestamp < ttl) {
                        return result;
                    }
                }
                
                const result = Reflect.apply(target, thisArg, args);
                cache.set(key, [result, now]);
                return result;
            }
        });
    }
}

// 使用示例
const expensiveOperation = CachingProxy.createCached(
    (x, y) => {
        console.log('执行计算...');
        return x + y;
    }
);

最佳实践 ⭐

  1. 结合Reflect API使用
javascript">// 推荐
const handler = {
    get(target, prop, receiver) {
        return Reflect.get(target, prop, receiver);
    }
};

// 不推荐
const handler = {
    get(target, prop) {
        return target[prop];
    }
};
  1. 合理使用代理链
javascript">function createProxyChain(...handlers) {
    return (target) => {
        return handlers.reduce((proxy, handler) => {
            return new Proxy(proxy, handler);
        }, target);
    };
}
  1. 错误处理
javascript">const handler = {
    get(target, prop, receiver) {
        try {
            return Reflect.get(target, prop, receiver);
        } catch (error) {
            console.error(`获取属性 ${prop} 失败:`, error);
            return undefined;
        }
    }
};

性能考虑 ⚡

  1. 避免过度代理
javascript">// 不推荐
function createProxy(obj) {
    return new Proxy(obj, {
        get: (target, prop) => Reflect.get(target, prop)  // 无意义的代理
    });
}

// 推荐
function createProxy(obj) {
    return obj;  // 如果不需要拦截,直接返回原对象
}
  1. 缓存代理结果
javascript">class ProxyCache {
    constructor() {
        this.cache = new WeakMap();
    }
    
    createProxy(target, handler) {
        if (this.cache.has(target)) {
            return this.cache.get(target);
        }
        
        const proxy = new Proxy(target, handler);
        this.cache.set(target, proxy);
        return proxy;
    }
}
  1. 合理使用可撤销代理
javascript">function createRevocableProxy(target, handler) {
    const { proxy, revoke } = Proxy.revocable(target, handler);
    
    // 在不需要时撤销代理
    setTimeout(() => {
        revoke();
    }, 5000);
    
    return proxy;
}

总结 📝

JavaScript的Proxy API提供了:

  1. 强大的对象操作拦截能力
  2. 灵活的代理模式实现方式
  3. 与Reflect API的完美配合
  4. 丰富的实际应用场景

💡 学习建议:

  • 深入理解各种代理拦截器
  • 掌握常用代理模式
  • 注意性能影响
  • 合理使用代理链
  • 始终做好错误处理

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻


http://www.niftyadmin.cn/n/5857521.html

相关文章

前端知识速记 - CSS篇:可继承属性与不可继承属性

前端知识速记 - CSS篇&#xff1a;可继承属性与不可继承属性 可继承属性 特点&#xff1a; 文本相关性&#xff1a;大多数可继承属性与文本样式相关&#xff0c;用于定义文本的外观。比如 color、font-family 和 font-size 等。 结构简化&#xff1a;通过继承父元素的样式&a…

神经网络实验——MLP

目录 1 目的 2 方法 3 源代码 4 结果 1 目的 ①熟悉 Python 的输入输出流; ②学会使用 matplotlib进行图像可视化; ③掌握神经网络的基本原理&#xff0c;学会使用 sklearn 库中的 MLPClassifier 函数构建基础的多层感知机神经网络分类器; ④学会使用网格查找进行超参数优…

什么是Embedding、RAG、Function calling、Prompt engineering、Langchain、向量数据库? 怎么使用

什么是Embedding、RAG、Function calling、Prompt engineering、Langchain、向量数据库? 怎么使用 目录 什么是Embedding、RAG、Function calling、Prompt engineering、Langchain、向量数据库? 怎么使用Embedding(嵌入)RAG(检索增强生成)Function calling(函数调用)Pr…

力扣 跳跃游戏 II

贪心算法&#xff0c;存下每一步的最远&#xff0c;去达到全局的最小跳跃次数。 题目 从题中要达到最少次数&#xff0c;肯定是每一步尽可能走远一点。但注意j被限制了范围&#xff0c;这种不用想每一步遍历时肯定选最大的num[i]&#xff0c;但要注意&#xff0c;题中是可以到…

【分布式理论13】分布式存储:数据存储难题与解决之道

文章目录 一、数据存储面临的问题二、RAID磁盘阵列的解决方案1. RAID概述2. RAID使用的技术3. RAID的代表性等级 三、分布式存储的新思路1. 分布式存储背景与特点2. 分布式存储的组成要素 一、数据存储面临的问题 在单机系统时代&#xff0c;当数据量不断增加、硬盘空间不够时…

BERT 大模型

BERT 大模型 EmbeddingTransformer预微调模块预训练任务 BERT 特点 : 优点 : 在语言理解相关任务中表现很好缺点 : 更适合 NLU 任务&#xff0c;不适合 NLG 任务 BERT 架构&#xff1a;双向编码模型 : Embedding 模块Transformer 模块预微调模块 Embedding Embedding 组成 …

异常处理、事务管理

异常处理 程序开发过程中不可避免的会遇到异常现象 如何处理 方案一&#xff1a;在Controller的方法中进行try...catch处理&#xff08;代码臃肿&#xff0c;不推荐&#xff09; 方案二&#xff1a;全局异常处理器 全局异常处理器 RestControllerAdvice &#xff1a;定义全…

GitLab 概念

GitLab 是一个基于 Git 的 DevOps 平台&#xff0c;提供了版本控制、持续集成/持续交付&#xff08;CI/CD&#xff09;、代码审查、项目管理等一系列功能。它帮助开发团队在整个软件生命周期中进行协作和管理。 具体来说&#xff0c;GitLab 提供以下功能&#xff1a; 版本控制…