发布时间:2025-12-10 19:23:25 浏览次数:8
Proxy 代理_在线代理软件Proxy代理1.Proxy代理创建Proxy对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义ES6原生提供Proxy构造函数,用来生成Proxy实例,Proxy对象需要传入两个参数target——被代理的目标对象,可以是任何东西,包括函数handler——代理配置,带有捕捉器即拦截操作的方法的对象,内部可以定义零个或多个代理函数letproxy=newProxy(target,handler)如果handler没有设置拦截,所有对
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例,Proxy对象需要传入两个参数
target —— 被代理的目标对象,可以是任何东西,包括函数 handler —— 代理配置,带有捕捉器即拦截操作的方法的对象,内部可以定义零个或多个代理函数 let proxy = new Proxy(target, handler) 是否还在为Ide开发工具频繁失效而烦恼,来吧关注以下公众号获取最新激活方式。亲测可用!
【正版授权,激活自己账号】:Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】:官方授权 正版激活 自己使用,支持Jetbrains家族下所有IDE…
如果handler 没有设置拦截,所有对 proxy 的操作都直接转发给了 target 目标对象 // 创建代理let obj = { };let proxy = new Proxy(obj, { });// 没有设置捕捉器则会将proxy操作直接转发给targetproxy.name = 'jsx';console.log(proxy); // Proxy {name: 'jsx'} Proxy 支持的 13 种拦截方法:
| 拦截器 | 描述 |
|---|---|
| get(target, propKey, receiver) | 拦截对象属性的读取 |
| set(target, propKey, value, receiver) | 拦截对象属性的设置,返回一个布尔值 |
| has(target, propKey) | in 操作符的捕捉器,返回一个布尔值 |
| deleteProperty(target, propKey) | delete 操作符的捕捉器,返回一个布尔值 |
| ownKeys(target) | 拦截 Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in 循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys() 的返回结果仅包括目标对象自身的可遍历属性 |
| getOwnPropertyDescriptor(target, propKey) | 拦截 Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象 |
| defineProperty(target, propKey, propDesc) | 拦截 Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值 |
| preventExtensions(target) | 拦截 Object.preventExtensions(proxy),返回一个布尔值 |
| getPrototypeOf(target) | 拦截 Object.getPrototypeOf(proxy),返回一个对象 |
| isExtensible(target) | 拦截 Object.isExtensible(proxy),返回一个布尔值 |
| setPrototypeOf(target, proto) | 拦截 Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截 |
| apply(target, object, args) | 拦截 Proxy 实例作为函数调用的操作,proxy(...args)、proxy.call(object, ...args)、proxy.apply(...) |
| construct(target, args, newTarget) | 拦截 Proxy 实例作为构造函数调用的操作,new proxy(...args) |
get(target, property, receiver)
该方法用于拦截某个属性的读取操作
target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy property —— 目标属性名 receiver —— 如果目标属性是一个 getter 访问器属性,则 receiver 就是本次读取属性所在的 this 对象,通常是 proxy 实例本身 // get(target, property, receiver) 读取属性let obj = { name: 'jsx'}let proxy = new Proxy(obj, { get(target, property, receiver) { if (property in target) return target[property]; }})console.log(proxy.name); // jsx 如果一个属性不可配置且不可写,则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错
// 当一个对象不可读不可写 proxy则不能修改属性let obj1 = Object.defineProperties({ }, { name: { value: 'ljj', writable: false, configurable: false }})let proxy1 = new Proxy(obj1, { get(target, property, receiver) { // 原对象不可写不可配置,代理对象proxy则不可修改 // return 'ljj' return target[property] }});console.log(proxy1.name); // ljj set(target, property, value, receiver)
该方法用来拦截对象属性的设置
target —— 是目标对象,该对象被作为第一个参数传递给 new Proxy property —— 目标属性名称 value —— 目标属性的值 receiver —— 与 get 捕捉器类似,仅与 setter 访问器属性相关,通常是 proxy 实例本身 set 拦截无论成功或者失败应当返回一个布尔值,在严格模式中,set 拦截器如果没有返回true,就会报错,set代理返回false或者undefined,都会报错
let obj = { name: 'jsx'};let proxy = new Proxy(obj, { set(target, property, value, receiver) { if (typeof value == 'string') { // 属性值必须是字符串才能赋值 target[property] = value; return true } else { return false } }})proxy.name = 'ljj';console.log(proxy.name); // 设置false后不会报错 无改变 如果目标对象自身的某个属性不可写,那么 set 方法将不会生效
对二级或以上的属性修改并不会触发 set 拦截器
// 对象属性不可写。set拦截器不会生效let obj1 = Object.defineProperty({ }, 'name', { value: 'jsx', writable: false})let proxy1 = new Proxy(obj1, { set(target, property, value, receiver) { if (typeof value == 'string') { target[property] = value; return true } else { return false } }})proxy1.name = 22;// 对二级以上属性,set拦截器不会触发proxy1.name.title = 'javascript';console.log(obj1.name); // jsx apply(target, object, args)
函数调用、call 和 apply 操作时会被 apply 拦截器拦截
target —— 目标对象 object —— 目标对象的上下文对象(this) args —— 目标对象的参数数组 let proxy = new Proxy(fn, { apply(target, object, args) { console.log(args) return fn(...args) * 2 }})function fn(item1, item2) { return item1 + item2}console.log(proxy(3, 4)); // 14console.log(proxy.call(null, 6, 4)); // 20console.log(proxy.apply(null, [9, 4])); // 26 has(target, propKey)
方法用来拦截 hasOwnProperty 操作与 in运算符,即判断对象是否具有某个属性时触发,has 方法只能返回布尔值,return 非布尔值会自动转成布尔值
target —— 目标对象
propKey —— 需查询的属性名
// has 用来拦截对象是否有某个属性let obj = { name: 'jsx', title: 'has'}let proxy = new Proxy(obj, { has(target, prop) { if (prop in target) { // 只能返回布尔值,反回非布尔值会自动转换为布尔值 return true } return false }})console.log('name' in proxy); // true// for in 循环不会触发has拦截器for (let item in proxy) { console.log(item)}// hasOwnProperty 不会触发has拦截器obj.hasOwnProperty('name') has()方法不判断一个属性是对象自身的属性,还是继承的属性,hasOwnProperty()和 for...in 都不能触发 has 方法
如果原对象不可配置或者禁止扩展,这时has() 拦截会报错
// 对象不可配置或者禁止扩展 has()会报错let obj1 = { message: 'jsx'};// 对象不可扩展,不可配置Object.preventExtensions(obj1);Object.seal(obj1)let proxy1 = new Proxy(obj1, { // has 拦截不可扩展,不可配置对象会报错 has(target, prop) { if (prop in target) { // 只能返回布尔值,反回非布尔值会自动转换为布尔值 return true } return false }})console.log('message' in proxy1); // Uncaught TypeError construct(target, args, newTarget)
用于拦截new命令,当构造函数使用 new 关键调用时拦截
construct() 方法返回的必须是一个对象,否则会报错
construct() 拦截的是构造函数,所以它的目标对象必须是函数,否则就会报错
target —— 目标对象 args —— 构造函数的参数数组 newTarget —— 创造实例对象时,new命令作用的构造函数 function User(arg) { console.log(arg)}// 必须拦截的是函数let proxy = new Proxy(User, { construct(target, args, newTarget) { console.log(args); // jsx return { value: 'abc' } // return 1; // 必须返回对象 }})let result = new proxy('jsx');console.log(result.value); // abc deleteProperty(target, propKey)
target —— 目标对象 propKey —— 需删属性名 用于拦截 delete 操作,只能返回布尔值,非布尔值会被转成布尔值
如果这个方法抛出错误或者返回 false,当前属性就无法被delete命令删除
// deleteProperty 拦截 delete 操作let obj = { title: 'js'};let proxy = new Proxy(obj, { deleteProperty(target, prop) { if (prop === 'title') { // 只能返回布尔值,非布尔值会被转成布尔值 delete target[prop] return true } else { return false } }});console.log(delete proxy.title); // true defineProperty(target, propKey, descriptor)
该方法拦截 Object.defineProperty() ,Object.defineProperties()、obj.prop = 'value' 等修改或者添加对象属性操作
target —— 目标对象 propKey —— 待检索其描述的属性名 descriptor —— 待定义或修改的属性的描述符 该方法只能返回布尔值,非布尔值会转成布尔值,返回 fasle 会导致报错
let obj = { title: 'js'}// 拦截defineProperty操作 let proxy = new Proxy(obj, { defineProperty(target, prop, descript) { console.log(descript) return true }})console.log(Object.defineProperty(proxy, 'title', { value: 'vue'}))console.log(proxy.lesson = 'react') 如果目标对象不可扩展,则 defineProperty()不能增加目标对象上不存在的属性
如果目标对象的某个属性不可写或不可配置,则defineProperty()方法不可以改变这两个设置
let obj1 = { lesson: 'js'};// 目标不可扩展,defineProperty不可添加不存在属性// Object.preventExtensions(obj1)// 不可写或不可配置, 代理后的对象不可改变这两个属性Object.defineProperty(obj1, 'lesson', { value: 'js', writable: false, configurable: false})let proxy1 = new Proxy(obj1, { defineProperty(target, prop, descript) { console.log(descript) return true }})// Uncaught TypeError 不可扩展// console.log(proxy1.name = 'jsx')// console.log(Object.defineProperty(proxy1, 'lesson', { // value: 'vue',// writable: true,// enumerable: true// })) // Uncaught TypeError getOwnPropertyDescriptor(target, propKey)
方法拦截 Object.getOwnPropertyDescriptor(),Object.getOwnPropertyDescriptors() 返回一个属性描述对象或者undefined
target —— 目标对象 propKey —— 待检索其描述的属性名 若返回值不是 undefined,则返回值必须是包含configurable 为 true 的对象,该值为 false 或省略会导致报错,若其他描述符未定义,以默认值填充,如果返回对象包含除描述符以外的属性,则该属性被忽略
// 方法拦截 Object.getOwnPropertyDescriptor 操作let obj = { name: 'jsx'};let proxy = new Proxy(obj, { getOwnPropertyDescriptor(target, prop) { return undefined }})// 可以返回undefinedconsole.log(Object.getOwnPropertyDescriptor(proxy, 'name')); // undefined// {configurable: true} 属性值必须为true 返回false报错let obj1 = { name: 'jsx'}let proxy1 = new Proxy(obj1, { getOwnPropertyDescriptor(target, prop) { return { configurable: true } }})console.log(Object.getOwnPropertyDescriptor(proxy1, 'name'));// {value: undefined, writable: false, enumerable: false, configurable: true}let obj2 = { name: 'jsx'}let proxy2 = new Proxy(obj2, { getOwnPropertyDescriptor(target, prop) { // return { configurable: false } // 不能返回false }})// 报错 Uncaught TypeErrorconsole.log(Object.getOwnPropertyDescriptor(proxy2, 'name')); getPrototypeOf(target)
主要用来拦截获取对象原型,拦截下面这些操作
__proto__ Object.prototype.isPrototypeOf() Object.getPrototypeOf() Reflect.getPrototypeOf() instanceof getPrototypeOf() 方法的返回值必须是对象或者null,否则报错
如果目标对象不可扩展, getPrototypeOf() 方法必须返回目标对象的原型对象
// getPrototypeOf 来拦截获取对象原型// Object.prototype.__proto__// Object.prototype.isPrototypeOf()// Object.getPrototypeOf()// Reflect.getPrototypeOf()// instanceoflet obj = { name: 'jsx'}let proxy = new Proxy(obj, { getPrototypeOf(target) { return { message: '截获取对象原型' } }})console.log(obj.__proto__);console.log(proxy.__proto__); //{message: '截获取对象原型'}console.log(Object.getPrototypeOf(obj));console.log(Object.getPrototypeOf(proxy)); // {message: '截获取对象原型'}console.log(Object.prototype.isPrototypeOf(obj)); // trueconsole.log(Object.prototype.isPrototypeOf(proxy)); // trueconsole.log(obj instanceof Object) // trueconsole.log(proxy instanceof Object); // trueconsole.log(Reflect.getPrototypeOf(obj))console.log(Reflect.getPrototypeOf(proxy)); // {message: '截获取对象原型'} isExtensible(target)
拦截 Object.isExtensible() 操作
该方法只能返回布尔值,否则返回值会被自动转为布尔值
这个方法有一个强限制,它的返回值必须与目标对象的 isExtensible 属性保持一致,否则就会抛出错误
// isExtensible(target)let obj = { name: 'jsx'};let proxy = new Proxy(obj, { isExtensible(target) { // 自动转为布尔值 return true }})// 返回值必须与目标对象的isExtensible属性保持一致 否则报错Object.preventExtensions(obj)console.log(Object.isExtensible(obj)); // falseconsole.log(Object.isExtensible(proxy)); // true 报错 ownKeys(target)
ownKeys()方法用来拦截对象自身属性的读取操作,拦截以下操作
Object.getOwnPropertyNames(obj) 返回非 Symbol 键 Object.getOwnPropertySymbols(obj) 返回 Symbol 键 Object.keys/values() 返回带有 enumerable 标志的非 Symbol 键/值 for..in 循环遍历所有带有 enumerable 标志的非 Symbol 键,以及原型对象的键 使用Object.keys()方法时,有三类属性会被 ownKeys() 方法自动过滤,不会返回
Symbol 值 不可遍历enumerable的属性 let obj = { name: 'jsx', [Symbol('title')]: 'javascript', message: 'thanks', type: true};Object.defineProperty(obj, 'type', { value: true, enumerable: false})let proxy = new Proxy(obj, { ownKeys(target) { // 不存在的属性,属性名为Symbol值,不可遍历enumerable的属性 ownkeys不会返回 return ['name', 'message', 'asd', Symbol('title')] }})console.log(Object.keys(obj)); // ['name', 'message']console.log(Object.keys(proxy)); // ['name', 'message'] ownKeys()方法返回的数组成员,只能是字符串或 Symbol 值。如果有其他类型的值,或者返回的根本不是数组,就会报错
如果目标对象自身包含不可配置的属性,则该属性必须被ownKeys()方法返回,否则报错
如果目标对象是不可扩展的,这时 ownKeys() 方法返回的数组之中,必须包含原对象的所有属性,且不能包含多余的属性,否则报错
let obj1 = { };Object.defineProperty(obj1, 'info', { configurable: false, enumerable: true, value: 10})Object.preventExtensions(obj1)let proxy1 = new Proxy(obj1, { ownKeys: function(target) { // 只能是字符串或 `Symbol` 值 // return [123, true, undefined, null, {}, []]; // 自身包含不可配置的属性必须被ownKeys()方法返回否则报错 // return ['info', 'name', Symbol('title')] // 如果目标对象是不可扩展的ownKeys()方法返回的数组之中,必须包含原对象的所有属性,且不能包含多余的属性,否则报错 return ['info'] }});console.log(Object.getOwnPropertyNames(proxy1)); // ['info', 'name'] preventExtensions(target)
拦截Object.preventExtensions() 操作,方法必须返回一个布尔值,否则会被自动转为布尔值
这个方法有一个限制,只有目标对象不可扩展时 Object.isExtensible(proxy) 为false,proxy.preventExtensions 才能返回true,否则会报错
// 当目标对象不可扩展时, preventExtensions才能返回truelet obj = { };let proxy = new Proxy(obj, { preventExtensions(target) { console.log('不可扩展') Object.preventExtensions(target) return true }});console.log(Object.preventExtensions(proxy)) setPrototypeOf(target, proto)
target —— 目标对象 proto —— 对象原型属性 主要用来拦截 Object.setPrototypeOf() 方法
只要修改 target 的原型对象,就会报错
该方法只能返回布尔值,否则会被自动转为布尔值。另外,如果目标对象不可扩展,setPrototypeOf() 方法不能改变目标对象的原型
// 主要用来拦截Object.setPrototypeOf()方法let obj = { };let proxy = new Proxy(obj, { setPrototypeOf(target, proto) { console.log(proto); // {title: 'jsx'} return true }})let proto = { title: 'jsx'}console.log(Object.setPrototypeOf(obj, proto))console.log(Object.setPrototypeOf(proxy, proto)) Proxy.revocable() 方法返回一个可取消的 Proxy 实例
let { proxy, revoke} = Proxy.revocable(target, handler) 该调用返回一个带有 proxy 和 revoke 函数的对象以将其禁用
revoke 属性是一个函数,可以取消Proxy实例,当执行 revoke 函数之后,再访问Proxy 实例,就会抛出一个错误
// revocable 取消代理let title = { name: 'jsx'};let { proxy, revoke } = Proxy.revocable(title, { get(target, prop, value) { return target[prop] }})console.log(proxy.name)// 取消代理revoke();console.log(proxy.name); // Uncaught TypeError Proxy 代理的情况下,目标对象内部的 this 关键字会指向 Proxy 代理,如果改变this指向,会导致 Proxy 无法代理目标对象 // Proxy代理下,目标对象内部this指向代理对象let title = { lesson: 'js', func: function() { console.log(this) }}title.func(); // {lesson: 'js', func: ƒ}let proxy = new Proxy(title, { })proxy.func(); // Proxy {lesson: 'js', func: ƒ}// 改变`this指向,会导致 Proxy无法代理目标对象let title1 = { lesson: 'js', func: function() { console.log(this.class) }}let title2 = { class: 'vue'}title1.func.call(title2); // vuelet proxy2 = new Proxy(title1, { })proxy2.func(); // undefined Proxy 拦截函数内部的 this,指向的是 handler 对象 get() 和 set() 拦截函数内部的 this,指向的都是 handler 对象 // 拦截器内部this 指向handler对象let obj = { name: 'jsx'};let proxy1 = new Proxy(obj, { get(target, prop, receiver) { console.log(this); // {get: ƒ} return target[prop] }, set(target, prop) { console.log(this); // {get: ƒ, set: ƒ} return true }})console.log(proxy1.name)console.log(proxy1.title = 'js')