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

什么是代理模式

代理模式(英语: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的兼容性

参考资料:

MDN---Proxy

实例解析ES6 Proxy使用场景

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

时间: 2018-01-05

浅谈es6语法 (Proxy和Reflect的对比)

如下所示: { //原始对象 let obj={ time:'2017-03-11', name:'net', _r:123 }; //(代理商)第一个参数代理对象,第二个参数真正代理的东西 let monitor=new Proxy(obj,{ // 拦截对象属性的读取 get(target,key){ return target[key].replace('2017','2018') }, // 拦截对象设置属性 set(target,key,value){ if(key==='name')

详细探究ES6之Proxy代理

前言 在ES6中,Proxy构造器是一种可访问的全局对象,使用它你可以在对象与各种操作对象的行为之间收集有关请求操作的各种信息,并返回任何你想做的.ES6中的箭头函数.数组解构.rest 参数等特性一经实现就广为流传,但类似 Proxy 这样的特性却很少见到有开发者在使用,一方面在于浏览器的兼容性,另一方面也在于要想发挥这些特性的优势需要开发者深入地理解其使用场景.就我个人而言是非常喜欢 ES6 的 Proxy,因为它让我们以简洁易懂的方式控制了外部对对象的访问.在下文中,首先我会介绍 Prox

ES6中Proxy代理用法实例浅析

本文实例讲述了ES6中Proxy代理用法.分享给大家供大家参考,具体如下: ES6中提出了一个新的特性,就是proxy,用来拦截在一个对象上的指定操作.这个功能非常的有用.举一个例子来说: var engineer = { name: 'Joe Sixpack', salary: 50 }; var interceptor = { set: function (receiver, property, value) { console.log(property, 'is changed to',

实例解析ES6 Proxy使用场景介绍

ES6 中的箭头函数.数组解构.rest 参数等特性一经实现就广为流传,但类似 Proxy 这样的特性却很少见到有开发者在使用,一方面在于浏览器的兼容性,另一方面也在于要想发挥这些特性的优势需要开发者深入地理解其使用场景.就我个人而言是非常喜欢 ES6 的 Proxy,因为它让我们以简洁易懂的方式控制了外部对对象的访问.在下文中,首先我会介绍 Proxy 的使用方式,然后列举具体实例解释 Proxy 的使用场景. Proxy,见名知意,其功能非常类似于设计模式中的代理模式,该模式常用于三个方面:

ES6中Proxy与Reflect实现重载(overload)的方法

本文实例讲述了ES6中Proxy与Reflect实现重载(overload)的方法.分享给大家供大家参考,具体如下: Proxy与Reflect实现重载(overload) 从语法角度讲JavaScript不支持重载.原因很简单,JS中函数可以传入任意类型.任意个数的参数,通通可以通过在函数内使用this.arguments获得.这样,就无法实现同名函数参数列表不同实现不同功能.当然,在实际使用过程中,可以人为去检测传入实参的个数及类型,来进行不同操作.但是,我认为这不能叫做重载. ES6带来了

Java中继承、多态、重载和重写介绍

什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上,通过增加新的方法或者重定义已有方法(下面会讲到,这种方式叫重写)的方式,产生一个新的类型.继承是面向对象的三个基本特征--封装.继承.多态的其中之一,我们在使用JAVA时编写的每一个类都是在继承,因为在JAVA语言中,java.lang.Object类是所有类最根本的基类(或者叫父类.超类),如果

老生常谈ES6中的类

前面的话 大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,这种状态一直延续到了ES5.由于类似的库层出不穷,最终还是在ECMAScript 6中引入了类的特性.本文将详细介绍ES6中的类 ES5近似结构 在ES5中没有类的概念,最相近的思路是创建一个自定义类型:首先创建一个构造函数,然后定义另一个方法并赋值给构造函数的原型 function PersonType(name) { this.name = name; } Person

PHP和JAVA中的重载(overload)和覆盖(override) 介绍

重载:同一个类中,函数名一样,返回值或者参数类型,个数不一样的叫做重载. 覆盖:同名函数,同返回值类型,同参数的叫做覆盖.指的是子类对父类中方法的覆盖. PHP不支持方法和操作符重载.JAVA不支持操作符的重载(但是"+"实际上是一种操作符重载). 复制代码 代码如下: <?php Class Father { public function fmeth1() { echo "fmeth1()...<br>"; } //public functio

ES6 proxy和reflect的使用方法与应用实例分析

本文实例讲述了ES6 proxy和reflect的使用方法.分享给大家供大家参考,具体如下: proxy和reflect都是es6为了更好的操作对象而提供的新的API,接下来探讨一下二者的作用,联系. 设计proxy,reflect的作用: proxy的作用: Proxy的设计目的在于(修改编程语言),修改某些操作方法的默认行为, 等同于在语言层面作出修改,是元编程(meta programming)  例如修改set,get方法 reflect的作用: 1,映射一些明显属于对象语言内部的方法,

深入理解 ES6中的 Reflect用法

Reflect对象是一个全局的普通的对象.Reflect的原型就是Object. 我们首先来验证下 看看Reflect的原型是否是Object, 基本代码如下: let obj = {}; console.log(Reflect.__proto__ === Object.prototype); // true console.log(obj.__proto__ === Reflect.__proto__); // true let str = '111'; console.log(str.__p