JavaScript拦截工具Proxy

在 JavaScript 中,Proxy 是一种强大的工具,它允许你通过拦截对象的基本操作(如属性访问、赋值、函数调用等)来定义自定义行为。Proxy 是在 ECMAScript 6(ES6)中引入的,主要用于增强对象的功能和行为。


基本语法

const proxy = new Proxy(target, handler);
  • target:需要代理的目标对象(可以是普通对象、数组或另一个 Proxy)。
  • handler:一个对象,包含特定操作的拦截方法(称为“trap”)。

常用 handler 的拦截方法(Trap)

以下是 Proxy 支持的常用 trap 方法,以及它们的用途:

Trap用途
get拦截属性读取,例如 proxy.prop
set拦截属性赋值,例如 proxy.prop = value
has拦截属性检查,例如 'prop' in proxy
deleteProperty拦截属性删除,例如 delete proxy.prop
ownKeys拦截对象自身属性的枚举,例如 Object.keys(proxy)for...in 循环。
apply拦截函数调用,例如 proxy()
construct拦截构造函数调用,例如 new proxy()

常见用法示例

1. 属性读取拦截
const person = {
    name: "Alice",
    age: 25
};

const proxy = new Proxy(person, {
    get(target, prop) {
        if (prop in target) {
            return target[prop];
        } else {
            return `Property "${prop}" does not exist.`;
        }
    }
});

console.log(proxy.name); // 输出: Alice
console.log(proxy.gender); // 输出: Property "gender" does not exist.

2. 属性赋值拦截(数据验证)
const person = {
    name: "Alice",
    age: 25
};

const proxy = new Proxy(person, {
    set(target, prop, value) {
        if (prop === "age" && typeof value !== "number") {
            throw new TypeError("Age must be a number.");
        }
        target[prop] = value;
        return true; // 必须返回 true,表示成功
    }
});

proxy.age = 30; // 正常赋值
console.log(proxy.age); // 输出: 30

proxy.age = "thirty"; // 抛出错误: Age must be a number

3. 日志记录
const person = {
    name: "Alice",
    age: 25
};

const proxy = new Proxy(person, {
    get(target, prop) {
        console.log(`Getting property "${prop}"`);
        return target[prop];
    },
    set(target, prop, value) {
        console.log(`Setting property "${prop}" to "${value}"`);
        target[prop] = value;
        return true;
    }
});

console.log(proxy.name); // 输出日志并获取值
proxy.age = 26; // 输出日志并更新值

4. 禁止删除属性
const person = {
    name: "Alice",
    age: 25
};

const proxy = new Proxy(person, {
    deleteProperty(target, prop) {
        if (prop === "name") {
            throw new Error("Cannot delete 'name'");
        }
        delete target[prop];
        return true;
    }
});

delete proxy.age; // 成功
console.log(proxy); // 输出: { name: 'Alice' }

delete proxy.name; // 抛出错误: Cannot delete 'name'

5. 拦截数组操作
const numbers = [1, 2, 3];

const proxy = new Proxy(numbers, {
    get(target, prop) {
        if (prop === "last") {
            return target[target.length - 1];
        }
        return target[prop];
    },
    set(target, prop, value) {
        if (prop === "length" && value < target.length) {
            throw new Error("Cannot shrink the array.");
        }
        target[prop] = value;
        return true;
    }
});

console.log(proxy.last); // 输出: 3
proxy.push(4); // 正常操作
console.log(proxy); // 输出: [1, 2, 3, 4]

proxy.length = 2; // 抛出错误: Cannot shrink the array.

6. 动态计算属性
const calculator = {
    factor: 2
};

const proxy = new Proxy(calculator, {
    get(target, prop) {
        if (prop === "double") {
            return target.factor * 2;
        }
        return target[prop];
    }
});

console.log(proxy.factor); // 输出: 2
console.log(proxy.double); // 输出: 4

总结

Proxy 提供了一种灵活的方式来拦截和自定义对象的行为,适用于以下场景:

  • 数据验证与保护
  • 动态属性计算
  • 日志记录或调试
  • 实现代理模式或权限控制

通过 Proxy,可以让代码更具可读性和功能性,同时也需要注意避免过度复杂的拦截逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值