JavaScript中的Proxy对象


Posted in Javascript onNovember 27, 2020

Js中Proxy对象

Proxy对象用于定义基本操作的自定义行为,例如属性查找、赋值、枚举、函数调用等。

语法

const proxy = new Proxy(target, handler);
  • target: 要使用Proxy包装的目标对象,可以是任何类型的对象,包括原生数组,函数,甚至另一个代理。
  • handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理proxy的行为。

描述

Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。这个词的原理为代理,在这里可以表示由它来代理某些操作,译为代理器。

var target = {a: 1};
var proxy = new Proxy(target, {
  set: function(target, key, value, receiver){ 
    console.log("watch");
    return Reflect.set(target, key, value, receiver);
  },
  get: function(target, key, receiver){ 
    return target[key];
  }
});
proxy.a = 11; // watch
console.log(target); // {a: 11}

Object.defineProperty是用于监听属性,而Proxy是监听整个对象,通过调用new Proxy(),可以创建一个代理用来替代另一个对象被称为目标,这个代理对目标对象进行了虚拟,因此该代理与该目标对象表面上可以被当作同一个对象来对待。代理允许拦截在目标对象上的底层操作,而这原本是Js引擎的内部能力,拦截行为使用了一个能够响应特定操作的函数,即通过Proxy去对一个对象进行代理之后,我们将得到一个和被代理对象几乎完全一样的对象,并且可以从底层实现对这个对象进行完全的监控。

// 常见的一道面试题 实现 a===1&&a===2&&a===3 为true

// Object.defineProperty 定义的是属性
// 可以实现对于题目的要求
var _a = 0;
Object.defineProperty(window, "a", {
  get:function(){
    return ++_a;
  }
})
console.log(a===1 && a===2 && a===3); // true

// proxy 代理的是对象 
// 因此在调用时实际与题目要求并不太相符
// 但同样也是一种实现方式
var _a = 0;
var proxy = new Proxy(window, {
  set: function(target, key, value, receiver){ 
    return Reflect.set(target, key, value, receiver);
  },
  get: function(target, key, receiver){
    if(key === "a") return ++_a;
    else return window[key];
  }
});
console.log(proxy.a===1 && proxy.a===2 && proxy.a===3); //true

方法

Proxy.revocable()

Proxy.revocable(target, handler)
Proxy.revocable()方法可以用来创建一个可撤销的代理对象,其返回一个包含了代理对象本身和它的撤销方法的可撤销Proxy对象。

  • target: 将用Proxy封装的目标对象,可以是任何类型的对象,包括原生数组,函数,甚至可以是另外一个代理对象。
  • handler: 一个对象,其属性是一批可选的函数,这些函数定义了对应的操作被执行时代理的行为。

该方法的返回值是一个对象,其结构为{"proxy": proxy, "revoke": revoke},一旦某个代理对象被撤销,它将变得几乎完全不可调用,在它身上执行任何的可代理操作都会抛出TypeError异常,注意可代理操作一共有14种,执行这14种操作以外的操作不会抛出异常。一旦被撤销,这个代理对象便不可能被直接恢复到原来的状态,同时和它关联的目标对象以及处理器对象都有可能被垃圾回收掉。再次调用撤销方法revoke()则不会有任何效果,但也不会报错。

var revocable = Proxy.revocable({}, {
 get: function(target, key) {
  return `[[ ${key} ]]`;
 }
});
var proxy = revocable.proxy;
console.log(proxy.example); // [[ example ]]
revocable.revoke();
// console.log(proxy.example); // 抛出 TypeError
// proxy.example = 1;      // 抛出 TypeError
// delete proxy.example;    // 抛出 TypeError
// typeof proxy         // "object",因为 typeof 不属于可代理操作

handler对象方法

handler对象是一个容纳一批特定属性的占位符对象,它包含有Proxy的各个捕获器trap。所有的捕捉器是可选的,如果没有定义某个捕捉器,那么就会保留源对象的默认行为。

  • handler.getPrototypeOf(): Object.getPrototypeOf方法的捕捉器。
  • handler.setPrototypeOf(): Object.setPrototypeOf方法的捕捉器。
  • handler.isExtensible(): Object.isExtensible方法的捕捉器。
  • handler.preventExtensions(): Object.preventExtensions方法的捕捉器。
  • handler.getOwnPropertyDescriptor(): Object.getOwnPropertyDescriptor方法的捕捉器。
  • handler.defineProperty(): Object.defineProperty方法的捕捉器。
  • handler.has(): in操作符的捕捉器。
  • handler.get(): 属性读取操作的捕捉器。
  • handler.set(): 属性设置操作的捕捉器。
  • handler.deleteProperty(): delete操作符的捕捉器。
  • handler.ownKeys(): Reflect.ownKeys、Object.getOwnPropertyNames、Object.keys、Object.getOwnPropertySymbols方法的捕捉器。
  • handler.apply(): 函数调用操作的捕捉器。
  • handler.construct(): new操作符的捕捉器。
var target = {
  a: 1,
  f: function(...args){
    console.log(...args);
  }
};
var proxy = new Proxy(target, {
  getPrototypeOf: function(target) {
    console.log("getPrototypeOf");
    return Object.getPrototypeOf(target);
  },
  setPrototypeOf: function(target, prototype) {
    console.log("setPrototypeOf");
    return Object.setPrototypeOf(target, prototype);
  },    
  isExtensible: function(target) {
    console.log("isExtensible");
    return Object.isExtensible(target);
  },
  preventExtensions: function(target) {
    console.log("preventExtensions");
    return Object.preventExtensions(target);
  },
  getOwnPropertyDescriptor: function(target, prop) {
    console.log("getOwnPropertyDescriptor");
    return Object.getOwnPropertyDescriptor(target, prop);
  },
  defineProperty: function(target, prop, descriptor) {
    console.log("defineProperty");
    return Object.defineProperty(target, prop, descriptor);
  },
  has: function(target, prop) {
    console.log("has");
    return prop in target;
  },
  get: function(target, prop, receiver) {
    console.log("get");
    return target[prop];
  },
  set: function(target, prop, value, receiver) {
    console.log("set");
    target[prop] = value;
    return true;
  },
  deleteProperty: function(target, property) {
    console.log("deleteProperty");
    delete target[property];
    return true;
  },
  ownKeys: function(target) {
    console.log("ownKeys");
    return Reflect.ownKeys(target);
  }
})


var proxyF = new Proxy(target.f, {
  construct: function(target, argumentsList, newTarget) {
    console.log("construct");
    return new target(...argumentsList);
  },
  apply: function(target, thisArg, argumentsList) {
    console.log("apply");
    return target.apply(thisArg, argumentsList);
  },

})

const _prototype = {test: 1};
Object.setPrototypeOf(proxy, _prototype); // setPrototypeOf
console.log(Object.getPrototypeOf(proxy)); // getPrototypeOf // { test: 1 }

Object.preventExtensions(proxy); // preventExtensions
console.log(Object.isExtensible(proxy)); // isExtensible // false

Object.defineProperty(proxy, "a", {configurable: true}); // defineProperty
console.log(Object.getOwnPropertyDescriptor(proxy, "a")); // getOwnPropertyDescriptor // { value: 1, writable: true, enumerable: true, configurable: true }

proxy.a = 11; // set
console.log(proxy.a); // get // 11

console.log(Object.keys(proxy)); // ownKeys getOwnPropertyDescriptor getOwnPropertyDescriptor // [ 'a', 'f' ]
delete proxy.a; // deleteProperty
console.log("a" in proxy); // has // false

proxyF(1, 2, 3); // apply 1 2 3
new proxyF(1, 2, 3); // construct 1 2 3

每日一题

https://github.com/WindrunnerMax/EveryDay

以上就是JavaScript中的Proxy对象的详细内容,更多关于JavaScript Proxy对象的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript ECMA-262-3 深入解析.第三章.this
Sep 28 Javascript
jQuery EasyUI API 中文文档 - MenuButton菜单按钮使用介绍
Oct 06 Javascript
jquery鼠标滑过提示title具体实现代码
Aug 06 Javascript
Jquery异步提交表单代码分享
Mar 26 Javascript
JavaScript检测鼠标移动方向的方法
May 22 Javascript
js创建对象几种方式的优缺点对比
Sep 28 Javascript
js将字符串中的每一个单词的首字母变为大写其余均为小写
Jan 05 Javascript
关于js中的鼠标事件总结
Jul 11 Javascript
基于vue中对鼠标划过事件的处理方式详解
Aug 22 Javascript
node.js中process进程的概念和child_process子进程模块的使用方法示例
Feb 11 Javascript
创建nuxt.js项目流程图解
Mar 13 Javascript
JS一分钟在github+Jekyll的博客中添加访问量功能的实现
Apr 03 Javascript
详解JavaScript中的链式调用
Nov 27 #Javascript
在Vue中使用CSS3实现内容无缝滚动的示例代码
Nov 27 #Vue.js
vuex的数据渲染与修改浅析
Nov 26 #Vue.js
vue动态合并单元格并添加小计合计功能示例
Nov 26 #Vue.js
JavaScript用document.write()输出换行的示例代码
Nov 26 #Javascript
vue单元格多列合并的实现
Nov 26 #Vue.js
VUE项目实现主题切换的多种方法
Nov 26 #Vue.js
You might like
深入浅析Yii admin的权限控制
2016/08/31 PHP
IE、FF浏览器下修改标签透明度
2014/01/28 Javascript
js给网页加上背景音乐及选择音效的方法
2015/03/03 Javascript
javascript比较两个日期相差天数的方法
2015/07/23 Javascript
AngularJS路由实现页面跳转实例
2017/03/03 Javascript
在vue项目中,将juery设置为全局变量的方法
2018/09/25 Javascript
VUE 配置vue-devtools调试工具及安装方法
2018/09/30 Javascript
微信小程序实现基于三元运算验证手机号/姓名功能示例
2019/01/19 Javascript
基于vue-cli3创建libs库的实现方法
2019/12/04 Javascript
Vue中正确使用Element-UI组件的方法实例
2020/10/13 Javascript
针对Vue路由history模式下Nginx后台配置操作
2020/10/22 Javascript
[03:15]2014DOTA2国际邀请赛 专访国士无双信心满满
2014/07/12 DOTA
Python学习思维导图(必看篇)
2017/06/26 Python
python利用dir函数查看类中所有成员函数示例代码
2017/09/08 Python
Python实现图片滑动式验证识别方法
2017/11/09 Python
神经网络理论基础及Python实现详解
2017/12/15 Python
python+Splinter实现12306抢票功能
2018/09/25 Python
python实现控制台打印的方法
2019/01/12 Python
Pandas删除数据的几种情况(小结)
2019/06/21 Python
python3 反射的四种基本方法解析
2019/08/26 Python
浅谈tensorflow中Dataset图片的批量读取及维度的操作详解
2020/01/20 Python
用pushplus+python监控亚马逊到货动态推送微信
2021/01/29 Python
领先的钻石和订婚戒指零售商:Diamonds-USA
2016/12/11 全球购物
兰蔻美国官网:Lancome美国
2017/04/25 全球购物
Hotels.com英国:全球领先的酒店住宿提供商
2019/01/24 全球购物
校园报刊亭创业计划书
2014/01/02 职场文书
党员四风剖析材料
2014/08/27 职场文书
创先争优活动承诺书
2014/08/30 职场文书
市场营销工作计划书
2014/09/15 职场文书
一年级语文上册复习计划
2015/01/17 职场文书
退税申请报告怎么写
2015/05/18 职场文书
小学六一主持词开场白
2015/05/28 职场文书
家庭教育培训学习心得体会
2016/01/14 职场文书
高中16字霸气押韵班级口号集锦!
2019/06/27 职场文书
mybatis 解决从列名到属性名的自动映射失败问题
2021/06/30 Java/Android
Win11任务栏太宽了怎么办?一招解决Win11任务栏太宽问题
2021/11/21 数码科技