ECMAScript 6(18)Proxy代理 (对象的代理)

简述 :

  1. 用于修改对某个对象的属性的操作的默认行为;
  2. 返回值和原对象有一层代理的差异;
  3. 返回值还是基于原对象的一系列操作, 最终还是修改的原对象的值;
  4. 拦截对象的属性, 可以对其进行读取, 修改, 遍历等操作;
  5. 继承的属性, 拦截也有效果;

1.  Proxy代理

简单说就是对对象, 加了一层中间的操作 , 你访问属性和设置属性会经过一层中间加工.

1.1  语法

var proxy = new Proxy(target, handler);

参数 :

target : 目标对象,即拦截目标,可以是原生对象或者内置对象

 handler : 拦截配置,是一个对象。你对参数一拦截哪些属性,拦截后的操作如何,都是在这里配置的;

 简单示例 : 

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

proxy.time // 35
proxy.name // 35

 2.  实例方法

就是 handler 里面可以有哪些配置

方法说明
get(target, propKey, receiver)拦截对象属性的读取,比如proxy.fooproxy['foo']
set(target, propKey, value, receiver)拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。
has(target, propKey)拦截propKey in proxy的操作,返回一个布尔值。
deleteProperty(target, propKey)拦截delete proxy[propKey]的操作,返回一个布尔值。
ownKeys(target)拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in
getOwnPropertyDescriptor(target, propKey)拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
defineProperty(target, propKey, propDesc)拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。
preventExtensions(target)拦截Object.preventExtensions(proxy),返回一个布尔值。
getPrototypeOf(target)拦截Object.getPrototypeOf(proxy),返回一个对象。
isExtensible(target)拦截Object.isExtensible(proxy),返回一个布尔值。
setPrototypeOf(target, proto)拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args)拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)
construct(target, args)拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

参数统一说明 :

target :  目标对象

propKey 属性

value : 属性值

args : 参数 (数组形式)

receiver : proxy 实例本身(严格地说,是操作行为所针对的对象)(一般可省略)

下面是几个常用的方法

2.1   读取 get()

get(target, propKey, receiver)

参数 :

  1. 第一个参数是 目标对象
  2. 第二个参数是 属性
  3. 第三个参数是 proxy 实例本身

示例 :

var p = new Proxy(target, {
  get: function(target, property, receiver) {
      return target[property];   
  }
});
var foo = {a:1};
var bar = new Proxy(foo, {
    get: function (target, key, receiver) {
        return target[key];
    }
});

bar.a
//1

注意 : 一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。

 2.2  写入 set()

set(target, property, value, receiver)

参数 :

  1. 第一个参数是 目标对象
  2. 第二个参数是 属性
  3. 第三个参数是 属性值
  4. 第四个参数是 proxy 实例本身

示例 : 

let foo = {};
let bar = new Proxy(foo, {
    set(target, key, value, proxy){
        if (key === 'a') {
            console.log(foo === target);
            console.log(key, value);
        }
        target.lastModify = {
            key, value
        }
        target[key] = value;
    }
})
bar.a = 1;
console.log(bar.a);
console.log(bar.lastModify);
//true
//"a" 1
//1
//{key:"a", value:"1"}

bar.b = 10;
console.log(bar.b);
console.log(bar.lastModify);
//10
//{key:"b", value:"10"}

注意 :

1.  如果目标对象自身的某个属性,不可写且不可配置,那么set方法将不起作用

2.  严格模式下,set代理如果没有返回true,就会报错。

2.3  函数拦截 apply()

每当执行proxy函数(直接调用或callapply调用),就会被apply方法拦截。

 apply (target, context, args)

参数 :

  1. 第一个参数是 目标对象
  2. 第二个参数是 目标对象的上下文对象(this
  3. 第三个参数是 目标对象的参数数组

示例 :

var twice = {
  apply (target, ctx, args) {
    return Reflect.apply(...arguments) * 2;
  }
};
function sum (left, right) {
  return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30

2.4  拦截 new 命令 construct()

construct方法用于拦截new命令,下面是拦截对象的写法。

construct (target, args, newTarget)

参数 :

  1. 第一个参数是 目标对象
  2. 第二个参数是 构造函数的参数对象
  3. 第三个参数是 创造实例对象时,new命令作用的构造函数

示例 :

var p = new Proxy(function () {}, {
  construct: function(target, args, newTarget) {
    console.log('called: ' + args.join(', '));
    return { value: args[0] * 10 , newTarget};
  }
});

(new p(1)).value
// "called: 1"
// 10
console.log(new p().newTarget === p)
// true

 更多详细的使用方法戳 阮一峰ES6

3.  可取消的 Proxy 实例 Proxy.revocable()

Proxy.revocable(target, handler);

示例 : 

返回值是一个对象,他有两个属性,一个是proxy,就是Proxy的实例,另外一个是revoke,类型是函数,用于移除这个代理。

let target = {};
let handler = {
    get(target, key){
        console.log(key);
        return target[key];
    }
};

let obj = Proxy.revocable(target, handler);
console.log(obj);   //{proxy: Proxy, revoke: function}

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

obj.revoke();
console.log(obj.proxy.foo); // TypeError: Revoked

Proxy.revocable的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。

4.  this 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懂懂kkw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值