Js中Proxy对象
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 // falseObject.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 // 11console.log(Object.keys(proxy)); // ownKeys getOwnPropertyDescriptor getOwnPropertyDescriptor // [ 'a', 'f' ]
delete proxy.a; // deleteProperty
console.log("a" in proxy); // has // falseproxyF(1, 2, 3); // apply 1 2 3
new proxyF(1, 2, 3); // construct 1 2 3
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://juejin.im/post/6844903853867925517
https://www.cnblogs.com/kdcg/p/9145385.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Js中Proxy对象相关推荐
- Js中Reflect对象
Js中Reflect对象 Reflect是ES6起JavaScript内置的对象,提供拦截JavaScript操作的方法,这些方法与Proxy对象的handlers中的方法基本相同. 描述 Refle ...
- JS中集合对象(Array、Map、Set)及类数组对象的使用与对比
JS中集合对象(Array.Map.Set)及类数组对象的使用与对比 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java ...
- Js中Symbol对象
Js中Symbol对象 ES6引入了一种新的基本数据类型Symbol,表示独一无二的值,最大的用法是用来定义对象的唯一属性名,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方 ...
- Js中Array对象
Js中Array对象 JavaScript的Array对象是用于构造数组的全局对象,数组是类似于列表的高阶对象. 描述 在JavaScript中通常可以使用Array构造器与字面量的方式创建数组. c ...
- Js中Number对象
Js中Number对象 JavaScript的Number对象是经过封装从而能够处理数字值的对象,Number对象由Number()构造器以及字面量声明的值在转化为包装对象时创建,JavaScript ...
- Js中String对象
Js中String对象 String全局对象是一个用于字符串或一个字符序列的构造函数. 描述 创建一个字符串可以通过字面量的方式,通过字面量创建的字符串变量在调用方法的时候能够自动转化为临时的包装对象 ...
- Js中RegExp对象
Js中RegExp对象 RegExp对象表示正则表达式,是由普通字符和特殊字符也叫元字符或限定符组成的文字模板,用于对字符串执行模式匹配. 描述 创建一个RegExp对象通常有两种方式,一种是通过字面 ...
- js实现小时钟,js中Date对象的使用?
介绍一下js中Date对象的使用 dateObj = new Date() dateObj = new Date(dateValue) dateObj = new Date(year,month,da ...
- js中WINDOW对象中的location成员对象
js中DOM, DOCUMENT, BOM, WINDOW 区别 全栈工程师开发手册 (作者:栾鹏) js系列教程6-BOM操作全解 js中WINDOW对象中的location成员对象 locatio ...
最新文章
- 微信小程序 下拉刷新页面时的加载状态
- Highcharts图表-ajax-获取json数据生成图表
- openfire消息通知推送_APP消息推送功能之前端后台设计
- 【C++学习详细教程目录】
- pytorch学习笔记(4):tensorboard可视化
- 开机先看广告!智能电视这流氓操作被整治,这家厂商败诉
- spring-aop 的注释用法
- Python随机梯度下降法(三)
- 基于Redis的微博关注与粉丝
- Android开源库--ActiveAndroid(active record模式的ORM数据库框架)
- Kafka 如何保证消息全局有序
- centos 6.5 找回root密码的方法
- 计算机专业毕业设计的进度记录,毕业设计周次进度计划及实际进展情况表.doc...
- 优质短信api接口具备的特点
- 【C代码】结构体数组初始化的相关总结
- 智能建造与建筑工业化协同发展主战场之一:攻克核心工业软件
- MySQL数据库备份的三种方式
- layui模板引擎的使用1
- HiKey试用体验 烧写系统至Flash之诡异事件
- 为什么计算机内存数值存储方式是补码?
热门文章
- 《Go语言程序设计》读书笔记(六) 基于共享变量的并发
- 客户端通过SSH private key 登录远端服务器
- 使用jmap来生成堆转储快照
- 数学通大道,算法合自然?
- PHP Fatal error: Class 'com' not found in ... 的处理办法
- SqlServer判断数据库、表、字段、存储过程、函数是否存在
- PetShop4.0的安装、设置、调试与体验(草稿)
- 一个ubuntu server下的oracle10g简单生产库全库备份脚本
- 我的宝贝干女儿--可可
- 基于注意力机制的知识图谱关系预测 ACL 2019