详解ES6中的代理模式——Proxy


Posted in Javascript onJanuary 08, 2018

什么是代理模式

代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。

所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法复制的资源。

著名的代理模式例子为引用计数(英语:reference counting)指针对象。

当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少内存用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。

上面是维基百科中对代理模式的一个整体的定义.而在JavaScript中代理模式的具体表现形式就是ES6中的新增对象---Proxy

什么是Proxy对象

在MDN上对于 Proxy 的解释是:

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

简单来说: Proxy 对象就是可以让你去对JavaScript中的一切合法对象的基本操作进行自定义.然后用你自定义的操作去覆盖其对象的基本操作.也就是当一个对象去执行一个基本操作时,其执行的过程和结果是你自定义的,而不是对象的.

:sweat:好吧,用文字表达可能太复杂了.我们还是直接上代码吧.

首先Proxy的语法是:

let p = new Proxy(target, handler);

其中:

  1. target 是你要代理的对象.它可以是JavaScript中的任何合法对象.如: (数组, 对象, 函数等等)
  2. handler 是你要自定义操作方法的一个集合.
  3. p 是一个被代理后的新对象,它拥有 target 的一切属性和方法.只不过其行为和结果是在 handler 中自定义的.

然后让我们来看这段代码:

let obj = {
 a: 1,
 b: 2,
}

const p = new Proxy(obj, {
 get(target, key, value) {
  if (key === 'c') {
   return '我是自定义的一个结果';
  } else {
   return target[key];
  }
 },

 set(target, key, value) {
  if (value === 4) {
   target[key] = '我是自定义的一个结果';
  } else {
   target[key] = value;
  }
 }
})
console.log(obj.a) // 1
console.log(obj.c) // undefined
console.log(p.a) // 1
console.log(p.c) // 我是自定义的一个结果
obj.name = '李白';
console.log(obj.name); // 李白
obj.age = 4;
console.log(obj.age); // 4
p.name = '李白';
console.log(p.name); // 李白
p.age = 4;
console.log(p.age); // 我是自定义的一个结果

从上面这段代码中,我可以很清楚的看到 Proxy 对象的作用.即是之前所受的 用于定义基本操作的自定义行为 .同样的 get 和 set 操作.没有没代理的对象所得的结果是其JavaScript本身的执行机制运行计算后所得到的.而被代理了的对象的结果则是我们自定义的.

Proxy所能代理的范围--handler

在上面代码中,我们看到了构造一个代理对象时所传的第二个参数 handler ,这个 handler 对象是由 get 和 set 两个函数方法组成的.这两个方法会在一个对象被 get 和 set 时被调用执行,以代替原生对象上的操作.那么为什么在 handler ,定义 get 和 set 这两个函数名之后就代理对象上的 get 和 set 操作了呢?

实际上 handler 本身就是ES6所新设计的一个对象.它的作用就是用来 自定义代理对象的各种可代理操作 。它本身一共有13中方法,每种方法都可以代理一种操作.其13种方法如下:

handler.getPrototypeOf()

// 在读取代理对象的原型时触发该操作,比如在执行 Object.getPrototypeOf(proxy) 时。

handler.setPrototypeOf()

// 在设置代理对象的原型时触发该操作,比如在执行 Object.setPrototypeOf(proxy, null) 时。

handler.isExtensible()

// 在判断一个代理对象是否是可扩展时触发该操作,比如在执行 Object.isExtensible(proxy) 时。

handler.preventExtensions()

// 在让一个代理对象不可扩展时触发该操作,比如在执行 Object.preventExtensions(proxy) 时。

handler.getOwnPropertyDescriptor()

// 在获取代理对象某个属性的属性描述时触发该操作,比如在执行 Object.getOwnPropertyDescriptor(proxy, "foo") 时。

handler.defineProperty()

// 在定义代理对象某个属性时的属性描述时触发该操作,比如在执行 Object.defineProperty(proxy, "foo", {}) 时。

handler.has()

// 在判断代理对象是否拥有某个属性时触发该操作,比如在执行 "foo" in proxy 时。

handler.get()

// 在读取代理对象的某个属性时触发该操作,比如在执行 proxy.foo 时。

handler.set()

// 在给代理对象的某个属性赋值时触发该操作,比如在执行 proxy.foo = 1 时。

handler.deleteProperty()

// 在删除代理对象的某个属性时触发该操作,比如在执行 delete proxy.foo 时。

handler.ownKeys()

// 在获取代理对象的所有属性键时触发该操作,比如在执行 Object.getOwnPropertyNames(proxy) 时。

handler.apply()

// 在调用一个目标对象为函数的代理对象时触发该操作,比如在执行 proxy() 时。

handler.construct()

// 在给一个目标对象为构造函数的代理对象构造实例时触发该操作,比如在执行new proxy() 时。

Proxy的作用

对于代理模式 Proxy 的作用主要体现在三个方面:

1、 拦截和监视外部对对象的访问

2、 降低函数或类的复杂度

2、 在复杂操作前对操作进行校验或对所需资源进行管理

而对于这三个使用方面的具体表现大家可以参考这篇文章-- 实例解析ES6 Proxy使用场景

Proxy的兼容性

详解ES6中的代理模式——Proxy

参考资料:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用jquery动态加载javascript以减少服务器压力
Oct 29 Javascript
使用JavaScript构建JSON格式字符串实现步骤
Mar 22 Javascript
jquery控制左右箭头滚动图片列表的实例
May 20 Javascript
jquery获取tagName再进行判断
May 29 Javascript
限制上传文件大小和格式的jQuery插件实例
Jan 24 Javascript
详解在vue-cli项目中安装node-sass
Jun 21 Javascript
vue自定义一个v-model的实现代码
Jun 21 Javascript
Vue之beforeEach非登录不能访问的实现(代码亲测)
Jul 18 Javascript
javascript设计模式 ? 简单工厂模式原理与应用实例分析
Apr 09 Javascript
解决vue项目router切换太慢问题
Jul 19 Javascript
JavaScript实现多球运动效果
Sep 07 Javascript
Vue使用CDN引用项目组件,减少项目体积的步骤
Oct 30 Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
Jan 08 #Javascript
实例解析ES6 Proxy使用场景介绍
Jan 08 #Javascript
详解weex默认webpack.config.js改造
Jan 08 #Javascript
关于vue单文件中引用路径的处理方法
Jan 08 #Javascript
浅谈React Native Flexbox布局(小结)
Jan 08 #Javascript
Node.js使用Koa搭建 基础项目
Jan 08 #Javascript
JavaScript体验异步更好的解决办法
Jan 08 #Javascript
You might like
据说是雅虎的一份PHP面试题附答案
2009/01/07 PHP
php中将时间差转换为字符串提示的实现代码
2011/08/08 PHP
DOM XPATH获取img src值的query
2013/09/23 PHP
PHP依赖倒置(Dependency Injection)代码实例
2014/10/11 PHP
php+ajax实现无刷新动态加载数据技术
2015/04/28 PHP
PHP文件操作实例总结
2016/09/27 PHP
javascript应用:Iframe自适应其加载的内容高度
2007/04/10 Javascript
读jQuery之六 缓存数据功能介绍
2011/06/21 Javascript
javascript nextSibling 与 getNextElement(node) 使用介绍
2011/10/13 Javascript
JS 仿腾讯发表微博的效果代码
2013/12/25 Javascript
使用jquery.upload.js实现异步上传示例代码
2014/07/29 Javascript
Javascript 赋值机制详解
2014/11/23 Javascript
javascript数据类型示例分享
2015/01/19 Javascript
jQuery获取标签文本内容和html内容的方法
2015/03/27 Javascript
快速学习AngularJs HTTP响应拦截器
2015/12/31 Javascript
关于 jQuery Easyui异步加载tree的问题解析
2016/12/06 Javascript
JS常见疑难点分析之match,charAt,charCodeAt,map,search用法分析
2016/12/25 Javascript
JavaScript箭头函数_动力节点Java学院整理
2017/06/28 Javascript
Bootstrap弹出框之自定义悬停框标题、内容和样式示例代码
2017/07/11 Javascript
一次记住JavaScript的6个正则表达式方法
2018/02/22 Javascript
基于layui数据表格以及传数据的方式
2018/08/19 Javascript
vue使用echarts图表自适应的几种解决方案
2020/12/04 Vue.js
[37:03]完美世界DOTA2联赛PWL S3 INK ICE vs GXR 第二场 12.16
2020/12/18 DOTA
对Python中数组的几种使用方法总结
2018/06/28 Python
Python JSON格式数据的提取和保存的实现
2019/03/22 Python
python实现图片中文字分割效果
2019/07/22 Python
pytorch 获取层权重,对特定层注入hook, 提取中间层输出的方法
2019/08/17 Python
深入CSS3 动画效果的总结详解
2013/05/09 HTML / CSS
10分钟理解CSS3 Grid布局
2018/12/20 HTML / CSS
phpquery中文手册
2021/03/18 PHP
ziaja齐叶雅官方海外旗舰店:来自波兰的天然护肤品牌
2017/01/02 全球购物
数据库面试要点基本概念
2013/10/31 面试题
安全员岗位职责范本
2015/04/11 职场文书
2015年小学生暑假总结
2015/07/13 职场文书
2016暑期社会实践新闻稿
2015/11/25 职场文书
MySQL 主从复制数据不一致的解决方法
2022/03/18 MySQL