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 相关文章推荐
永不消失的title提示代码
Feb 15 Javascript
基于jquery的tab切换 js原理
Apr 01 Javascript
javascript学习笔记(十三) js闭包介绍(转)
Jun 20 Javascript
jQuery实现可收缩展开的级联菜单实例代码
Nov 27 Javascript
判断JS对象是否拥有某属性的方法推荐
May 12 Javascript
基于JavaScript实现熔岩灯效果导航菜单
Jan 04 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(二)
Jan 21 Javascript
浅谈js使用in和hasOwnProperty获取对象属性的区别
Apr 27 Javascript
详解Node.js读写中文内容文件操作
Oct 10 Javascript
js使用formData实现批量上传
Mar 27 Javascript
基于JS开发微信网页录音功能的实例代码
Apr 30 Javascript
vue中node_modules中第三方模块的修改使用详解
May 31 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
PHP+AJAX实现无刷新注册(带用户名实时检测)
2007/01/02 PHP
PHP中“简单工厂模式”实例代码讲解
2012/09/04 PHP
PHP仿微信发红包领红包效果
2016/10/30 PHP
使用Yii2实现主从数据库设置
2016/11/20 PHP
PHP使用new StdClass()创建空对象的方法分析
2017/06/06 PHP
在Ubuntu 18.04上安装PHP 7.3 7.2和7.0的方法
2019/04/09 PHP
javascript的trim,ltrim,rtrim自定义函数
2008/09/21 Javascript
JQuery给元素添加/删除节点比如select
2013/04/02 Javascript
基于mouseout和mouseover等类似事件的冒泡问题解决方法
2013/11/18 Javascript
Jquery Uploadify上传带进度条的简单实例
2014/02/12 Javascript
JS判断变量是否为空判断是否null
2014/07/25 Javascript
JS+CSS实现仿新浪微博搜索框的方法
2015/02/24 Javascript
Nodejs关于gzip/deflate压缩详解
2015/03/04 NodeJs
node.js调用C++开发的模块实例
2015/07/03 Javascript
jQuery实现的仿select功能代码
2015/08/19 Javascript
JQuery移动页面开发之屏幕方向改变与滚屏的实现
2015/12/03 Javascript
jQuery插件实现文件上传功能(支持拖拽)
2020/08/27 Javascript
AngularJS Select(选择框)使用详解
2017/01/18 Javascript
angularjs下拉框空白的解决办法
2017/06/20 Javascript
JavaScript代码判断输入的字符串是否含有特殊字符和表情代码实例
2017/08/17 Javascript
360提示[高危]使用存在漏洞的JQuery版本的解决方法
2017/10/27 jQuery
vue router+vuex实现首页登录验证判断逻辑
2018/05/17 Javascript
vue计算属性+vue中class与style绑定(推荐)
2020/03/30 Javascript
ES2020系列之空值合并运算符 '??'
2020/07/22 Javascript
如何使用jQuery操作Cookies方法解析
2020/09/08 jQuery
[03:49]2016完美“圣”典风云人物:AMS专访
2016/12/06 DOTA
Python并发编程协程(Coroutine)之Gevent详解
2017/12/27 Python
python装饰器代替set get方法实例
2019/12/19 Python
tensorflow使用range_input_producer多线程读取数据实例
2020/01/20 Python
捐书寄语赠言
2014/01/18 职场文书
表决心的诗句大全
2014/03/11 职场文书
结婚保证书
2015/01/16 职场文书
秋收起义观后感
2015/06/11 职场文书
养成教育工作总结
2015/08/13 职场文书
Pandas搭配lambda组合使用详解
2022/01/22 Python
Java数组详细介绍及相关工具类
2022/04/14 Java/Android