javascript中的new Proxy使用详情

4 阅读2分钟

JavaScript的Proxy对象是一种强大且灵活的特性,它允许你拦截并自定义对对象执行的操作。自ECMAScript 6(ES6)引入以来,Proxy对象为控制对象的基本操作行为提供了一种机制,使高级用例和改进的安全性成为可能。

一.使用方法

new Proxy(target, handler),target为被代理对象handler为拦截器对象。

二.关于handler拦截器对象配置

可配置拦截器共13个分别如下

分类拦截器触发时机参数详解
属性读取/设置get读取属性target: 目标对象 property: 属性名 receiver: 指向本次读取操作所在的对象(通常是代理本身或继承代理的对象)
set设置属性target: 目标对象 property: 属性名 value: 新属性值 receiver: 最初被调用的对象(通常是代理本身)
属性存在性/删除hasin 操作符target: 目标对象 property: 需要检查是否存在的属性名 
deletePropertydelete 操作符target: 目标对象 property: 待删除的属性名 
属性/对象遍历ownKeysObject.keys()for...in 等获取属性键的方法target: 目标对象 
getOwnPropertyDescriptorObject.getOwnPropertyDescriptortarget: 目标对象 prop: 属性名 
函数/构造调用apply函数调用target: 目标对象(必须是函数) thisArg: 被调用时的 this 上下文 argumentsList: 被调用时的参数数组 
constructnew 操作符target: 目标对象(必须是构造函数) argumentsList: 构造函数的参数列表 newTarget: 最初被调用的构造函数 
原型/属性描述符getPrototypeOfObject.getPrototypeOftarget: 目标对象 
setPrototypeOfObject.setPrototypeOftarget: 目标对象 prototype: 对象的新原型或 null 
definePropertyObject.definePropertytarget: 目标对象 property: 属性名 descriptor: 属性的描述符对象 
对象扩展性isExtensibleObject.isExtensibletarget: 目标对象 
preventExtensionsObject.preventExtensionstarget: 目标对象

三.常用拦截器

1.get、set

const target = {
    name = 'jone',
    get value() {
        return name
    }
}
const handler = {
    get(target, property, receiver) {
        // 如果属性不存在,返回一个默认值 18,而不是 undefined
        if (property === 'age' && !(property in target)) {
          return 18; 
        }
        // 使用 Reflect 确保默认行为(例如访问原型链属性)
        return Reflect.get(target, property, receiver);
    },
    set(target, property, value, receiver) {
        // 可以在这里校验属性合理性
        if(property === 'age' && typeof value !== number) {
            throw new TypeError('age 必须是数字');
        }
        return Reflect.set(target, property, value, receiver)
    }
}
const p = new Proxy(target, handler)
console.log(p.value) // jone
console.log(p.age) // 18
p.age = 'tom' // Error age 必须是数字

2.apply

import axios from 'axios'

const isReadOnly = true; // 假设这是某个全局状态
// 请求接口前判断是否有权限继续请求
const handler = {
    apply(target, thisArg, argumentsList) {
        if(isReadOnly && ['post', 'put', 'delete'].includes(target.name)) {
            throw new Error("只读模式下禁止修改");
        }
    }
    return Reflect.apply(target, thisArg, argumentsList)
}

const get: <T>(...args: any) => Promise<T> = new Proxy(axios.get, handler);
const post: <T>(...args: any) => Promise<T> = new Proxy(axios.post, handler);
const put: <T>(...args: any) => Promise<T> = new Proxy(axios.put, handler);
const deleteRequest: <T>(...args: any) => Promise<T> = new Proxy(axios.delete, handler);