ES6学习笔记16:Proxy

本文详细介绍了ES6中的Proxy,它能修改对象操作的默认行为,实现元编程。Proxy通过构造函数生成实例,可以拦截get、set、apply、has等操作。get方法拦截属性读取,set方法拦截属性赋值,apply拦截函数调用,has拦截操作。Proxy.revocable()返回可取消的Proxy实例,适用于临时访问控制。然而,由于this指向问题,Proxy并非目标对象的完全透明代理,尤其在处理原生对象时。Proxy在Web服务客户端的应用非常广泛。
摘要由CSDN通过智能技术生成

Proxy用于修改一些操作的默认行为,等于在语言层面上作出修改,属于“元编程”,即:对编程语言进行编程。

基本用法

Proxy 提供一种可以对外界的访问进行过滤和改写的机制。

ES6原生提供Proxy构造函数,用来生成Proxy实例。

var proxy = new Proxy(target, handler);

Proxy对象的所有用法都是上面这种形式,不同的在于handler参数的写法。target参数表示所要拦截的目标对象,handler参数是一个对象,用来定制拦截行为。

var proxy = new Proxy({}, {
  get: function(target, propKey){
    return 35;
  }
});

console.log(proxy['time']); // 35

上面代码中,在没有Proxy的介入的情况下,操作本身是访问目标对象的,第二个参数配置对象,对于每一个被代理的操作需要提供一个对象的处理函数,这个函数将拦截对应的操作。在上面的代码中,配置对象有一个get方法,用来拦截对目标对象属性的访问请求,get方法的两个参数分别是目标对象和所要访问的属性。由于拦截函数总是返回35,所以访问任何属性得到35.

注意,要使Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标进行操作

  • handler没有设置任何拦截,那就等同于直接通向原对象了,没有任何拦截效果。
  • 可以将Proxy对象设置到object.proxy属性,从而可以在object对象上调用。
const object = { proxy: new Proxy(target, handler) };
  • Proxy实例也可以作为其他对象的原型对象
  • 同一个拦截器函数,可以设置多个操作

Proxy 实例的方法

get()
  • get():用于拦截某个属性的读取操作,可以接受三个参数,依次为对象、属性名和p roxy实例本身,最后一个参数为可选。
  • get()方法是可以继承的。
  • 如果一个属性不可配置,并且不可写,Proxy 不能修改这个属性,否则通过Proxy 对象访问这个属性会报错。
set()
  • Set()方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象,属性名,属性值和Proxy实例本身(参数可选).
  • 如果目标对象的某个属性,不可写且不可配置,那么set方法将不起作用。
  • 在严格模式下,set代理如果没有返回true,就会报错
apply()

方法apply方法拦截函数的调用,callapply操作

方法apply可以接受三个参数,分别是目标对象、目标上下文对象(this)和目标对象的参数数组

var target = function() {return 'this is target'};
var handler = {
  apply: function() {
    return 'this is proxy';
  }
}
var proxy = new Proxy(target, handler);

p() // 'this is proxy'
has()

方法has()用来拦截HasProperty操作,即:判断对象是否具有某个属性。典型的操作是in操作符

方法has()接受两个参数,分别是目标对象,需要查询的属性名

var handler = {
  has (target, key){
    if(key[0] === '_'){
      return false;
    }
    return key in target;
  }
};
var target = {_prop: 'foo', prop:'foo'};
var proxy = new Proxy(target, handler);
console.log('_proxy' in proxy); // false
  • has方法拦截的是HasProperty操作,而不是HasOwnProperty操作,has方法不判断一个属性是对象的自身的属性还是继承属性
  • has拦截对for...in循环不生效

Proxy.revocable()

方法Proxy.revocable()返回一个可取消的Proxy实例

const target = {};
const handler = {};
const {proxy, revoke} = Proxy.revocable(target, handler);

proxy.foo = 123;
console.log(proxy.foo); // 123

revoke();

console.log(proxy.foo); // TypeError

方法Proxy.revocable()返回一个对象,这个对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。

使用场景

目标对象不允许直接访问,必须通过代理访问,一旦访问结束就收回代理,不允许再次访问

this问题

Proxy可以代理针对目标对象的访问,但不是目标对象的透明代理,即:不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要是因为,Proxy代理的情况下,目标对象内部的this关键字会指向Proxy 代理,有些原生对象的内部属性,只有痛过正确的this才能拿到,所以,此时Proxy无法代理这些原生对象的属性。

Web服务的客户端

Proxy 对象可以拦截目标对象的任意属性,使得Proxy非常适合写Web服务的客户端。

function createWebService(baseUrl){
  return new Proxy({},{
    get(target, propKey,reveiver){
      return () => httpGet(baseUrl + '/' + propKey)
    }
  });
}

备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值