Proxy

用于创建一个对象的代理,方便拦截和重新定义该对象的基本操作

描述

Proxy允许创建一个对象来替代原始对象.但可以重新定义基本操作,比如 getting / setting 和定义属性.代理对象通常被用来记录属性访问,验证,格式化或清理输入

创建代理对象

const proxy = new Proxy(target,handler)
  • target : 要代理的对象

  • handler : 一个对象,用于定义那些操作江北拦截以及如何重新定义被拦截的操作

const target = {
  message1: "hello",
  message2: "everyone",
};

const handler1 = {};

const proxy1 = new Proxy(target, handler1);

上面的例子中,handler为空,新建立的proxy对象跟原始目标的行为相同.通过handler的定义,我们可以改变代理对象的一些行为使其与原始对象不同

const person = {
    name:"Apple",
    age:"18"
}

const handler = {
    get(target, prop receiver) {
        return "Apple is 18"
    }
}

cosnt proxy = new Proxy(person ,handler);

console.log(proxy.name);    // Apple is 18

这里拦截了代理对象的get方法使其返回的值固定 . handler中的函数被称作捕获器(traps),所以可以描述上面的代码为,捕获了代理对象的所有属性访问器并进行重新定义.

Reflect

代理通常Reflect 对象一起使用.该对象提供了一些Proxy 捕获器同名的方法来确保默认行为,只在需要修改的行为才自定义实现

const person = {
  name: 'John Doe',
  age: 30,
  occupation: 'Software Developer'
};
const handler={
  get(target, prop,receiver) {
    console.log(target, prop, receiver);
    if (prop==="name") {
      console.log(`Accessing property: ${prop}`);
      return "Benjamin";
    }
    return Reflect.get(target, prop, receiver);
  },
}
const porxy = new Proxy(person, handler);

console.log(porxy.name); // Benjamin

这样只有在访问name属性时才会执行自定义逻辑

关于handler内部具体有哪些捕获器可以看这篇文章https://halo.jiangling.site/archives/proxy-handler

Reflect 方法依然通过对象内部方法与对象交互------如果在Proxy的捕获函数中使Reflect :

const target = { name: 'Original' };
const proxy = new Proxy(target, {
  get(target, prop, receiver) {
    console.log(`Getting ${prop}`);
    // 危险操作:在陷阱内不加区分地使用Reflect
    return Reflect.get(...arguments);
  }
});

proxy.name; // 无限递归!

然而在Vue中这样写代码时并没有出现堆栈溢出的报错,这得益于V8引擎的优化,这里不再细说,但是一定要明白这样写是不安全的,要显示的指定参Reflect.get(target, prop, receiver) 或者直接省receiver 参数截断递归

对象内部方法

对象时属性的集合,但是JavaScript没有提供任何机制来直接操作存储在对象中的数据. 相反,对象在内部定义了一些内部方法,指定如何交互.

比如当读取 obj.x 时,:

  • 在原型链上寻找 x 属性,直到找到他

  • 如果 x 是数据属性,返回属性描述符的 value

  • 如果 x 是访问器属性,调用 getter 并返回 getter 的返回值

JavaScript中,对象内部定义了一个 [[Get]] 方法 , obj.x 属性访问语法知识在对象上调用 [[Get]] 方法 , 对象使用自身内部的方法实现来确定要返回的内容

[[Get]] 这种表示方法是一种有意的视觉区分,表示描述引擎行为的标准符号,而我们使用get() 这是描述开发者可调用的实际方法

所有对象内部都有一下方法

Internal method  内部方法

Corresponding trap  对应的陷阱

[[GetPrototypeOf]]

getPrototypeOf()

[[SetPrototypeOf]]

setPrototypeOf()

[[IsExtensible]]

isExtensible()

[[PreventExtensions]]

preventExtensions()

[[GetOwnProperty]]

getOwnPropertyDescriptor()

[[DefineOwnProperty]]

defineProperty()

[[HasProperty]]

has()

[[Get]]

get()

[[Set]]

set()

[[Delete]]

deleteProperty()

[[OwnPropertyKeys]]

ownKeys()

Function对象还具有一下内部方法

Internal method  内部方法

Corresponding trap  对应的陷阱

[[Call]]

apply()

[[Construct]]

construct()

需要认识到,与对象的所有交互最终都会归结到调用这些内部方法上.而通Proxy 可以对这些方法进行自定义. 这也意味着,JavaScript 中无法保证对对象的操作一定是预期的.

所有的内部方法都不能JavaScript 中直接调用Reflect 提供的方法除了进行一些输入的规范化/验证之外,也都是在调用内部方法. 我们在调用函数时,这个函数可能调用了很多个内部方法来实现,比如数组push() 就会调get() set() 捕获器


Proxy
https://halo.jiangling.site/archives/proxy
作者
你的降灵
发布于
2025年07月21日
许可协议