【ES6】Proxy对象

简介: 【ES6】Proxy对象
引言:ES6规范里面新增了Proxy对象,在高级范畴的js编程或者底层脚本的编写有这极强的作用。

一、Proxy的基本用法


     Proxy用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程"( meta programming),即对编程语言进行编程。

       Proxy可以理解成在目标对象前架设一“拦截”层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理"”某些操作,可以译为“代理器”。

       在介绍Proxy对象的基本用法之前,我们先来讲述一下JS中对象的机制。例如,我先简单的创建一个对象:var obj = {};,现在obj对象是没有属性的。假如我再写一条语句obj.id=1;,此时,虽然obj对象没有id这条属性,但是obj.id=1操作是调用了JS对象机制内部的set方法。

       下面,给出Proxy对象定义的基本格式:var proxy = new Proxy(target , handler);

Proxy对象的所有用法都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成个Proxy实例,target参数表示所要拦截的目标对象的名称,hander参数是一个函数方法,用来定制拦截行为。

       代码块1-1运用Proxy对象写了一个拦截对象对自己的属性进行赋值与取值的代理器。

/***@@    代码块1-1    拦截器举例一    @@***/
var obj = new Proxy({},{
  get: function (target, key, receiver) {
    console. log(`getting ${key}!`);
    return Reflect.get(target, key, receiver);
  },
  set: function (target, key, value, receiver) {
    console. log(`setting ${key}!`);
    return Reflect.set(target, key, value, receiver);
});
obj.count=1; 
// setting count!
++obj.count;
//getting count!
//setting count!
//2
代码块1-1解释:
首先,定义obj对象为Proxy类。
Proxy第一个参数应该是一个对象名,表示要拦截的目标对象,本例为空,则指向源对象obj。
Proxy第二个参数是自定义的拦截方法。
本例是对JS对象机制的get与set进行重定义,其中target参数是目标对象名,key是属性名。
当obj.count=1;代码运行时,首先会调用obj对象的set函数机制,然后被Proxy拦截,输出setting count!。
当obj.count++;运行时,先get到count的值,再去set。

     代码块1-1对一个空对象做了一层拦截,重定义了属性的读取(get)和设置(set)行为。Proxy 实际上重载(overlad)了点运算符,即用自己的定义覆盖了语言的盾始定义。

       下面是另一个拦截读取属性行为的例子。见代码块1-2。

/***@@    代码块1-2    拦截读取属性    @@***/
var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});
proxy.time // 35
proxy.nane // 35
proxy.title // 35

  上面的代码中,作为构造函数Proxy接受两个参数:第一个参数是所要代理的目标对象(上例中是一个空对象),即如果没有Proxy介人,操作原来要访问的就是这个对象;第二个参数是配置对象,对于每一个被代理的操作,需要提供一 个对应的处理函数,该函数将拦截对应的操作。比如,上面的代码中, 配置对象有一个get方法,用来拦截对目标对象属性的访问请求。get方法的两个参数分别是目标对象和所要访问的属性。可以看到,由于拦截函数总是返回35,所以访问任何属性都将得到35。

       注意,要使Proxy起作用,必须针对Proxy实例(上例中是proxy对象)进行操作,而不是针对目标对象(上例中是空对象)进行操作。

       如果handler没有设置任何拦截,那就等同于直接通向原对象。见代码块1-3。

/***@@    代码块1-3       @@***/
var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';
target.a // "b"

  上面的代码中,handler 是一个空对象,没有任何拦藏效果,访问hndler就等同于访问target。

       一个技巧是将 Proxy对象设置到object.proxy属性,从而可以在object对象上调用。

var object= { proxy: new Proxy(target, handler) }

二、Proxy示例的方法


1)get()

       get方法用于拦截某个属性的读取操作。前面已经有一个例子, 下面是另一个拦截读取操作的例子。见代码块2-1-1。

/***@@    代码块2-1-1       @@***/
var person = {
  name: "张三"
};
var proxy = new Proxy(person, {
  get: function(target, property) {
    if (property in target) {
      return target[property];
    } else {
      throw new ReferenceError("Property \"" + property + "\" does not  exist.");
    }
  }
});
proxy.name // "张三”
proxy.age //抛出一个错误

2)set()

       set方法用于拦截某个属性的赋值操作。

       假定Person对象有个age属性,该属性应该是个不大于200的整数,那么可以使用Porxy对象保证age的属性值符合要求。见代码块2-2-1。

/***@@    代码块2-2-1       @@***/
let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TyeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }
    //其他属性一律保存
    obj[prop] = value;
  }
};
let person = new Proxy({}, validator);
person.age = 100;
person.age // 100
person.age = 'young' //报错
person.age = 300 //报错

       上面的代码中,由于设置了存值函数set,任何不符合要求的age属性赋值都会抛出一个错误。利用set方法,还可以数据绑定,即每当对象发生变化时,会自动更新DOM。

       有时,我们会在对象上设置内部属性,属性名的第一个字符使用 下画线开头,表示这些属性不应该被外部使用。结合get和set方法,就可以做到防止这些内部属性被外部读写。

/***@@    代码块2-2-1   屏蔽下划线开头的属性    @@***/
var handler = {
  get (target, key) {
    invartant(key, 'get');
    return target[key];
  },
  set (target, key, value) {
    invartant(key, 'set');
    return true;
  }
} 
functton invartant (key, action) {
  if (key[0] === '_') {
    throw new Error(`Invalid attempt to ${action} private "${key}" property`);
    }
}
var target = {};
var proxy = new Proxy(target, handler);
proxy._prop
//Error: Invalid attempt to get private " prop" property
proxy._prop = 'c'
// Error: Invalid attempt to set private " prop" property

    上面的代码中,只要读写的属性名的第一个字符是下画线,一律抛出错误,从而达到禁止读/写内部属性的目的。

3)apply()

       apply方法拦截函数的调用、call和apply操作。形式如下:

var handler = {
apply (target, ctx, args) {
return Reflect. apply(…arguments);}
}

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

var target= function () { return 'I am the target'; };
var handler =
  apply: function () {
    return 'I am the proxy';
  };
var p = new Proxy(target, handler);
p() === 'I am the proxy';
// true

       上面的代码中,变量p是Proxy的实例,当作为函数调用时(p()),就会被apply方法拦截,返回一个字符串。

查看更多ES6教学文章:


1. 【ES6】let与const 详解

2. 【ES6】变量的解构赋值

3. 【ES6】字符串的拓展

4. 【ES6】正则表达式的拓展

5. 【ES6】数值的拓展

6. 【ES6】数组的拓展

7. 【ES6】函数的拓展

8. 【ES6】对象的拓展

9. 【ES6】JS第7种数据类型:Symbol

10. 【ES6】Proxy对象

11. 【ES6】JS的Set和Map数据结构

12. 【ES6】Generator函数详解

13. 【ES6】Promise对象详解

14. 【ES6】异步操作和async函数

15. 【ES6】JS类的用法class

16. 【ES6】Module模块详解

17. 【ES6】ES6编程规范 编程风格

参考文献


阮一峰 《ES6标准入门(第2版)》

相关文章
|
1天前
ES6的Proxy到底是什么?
ES6的Proxy到底是什么?
9 2
|
2月前
|
JavaScript 前端开发 API
什么是ES6的Proxy对象和Reactive API
【9月更文挑战第3天】什么是ES6的Proxy对象和Reactive API
27 8
|
3月前
|
JavaScript 前端开发
ES6新特性: Proxy
ES6新特性: Proxy
|
5月前
es6 proxy的作用和用法
es6 proxy的作用和用法
26 5
|
6月前
es6中proxy如何使用
es6中proxy如何使用
69 0
|
6月前
|
前端开发 JavaScript 数据安全/隐私保护
ES6 什么是Proxy?什么是Promise?
ES6 什么是Proxy?什么是Promise?
76 0
ES6 什么是proxy
ES6 什么是proxy
69 2
ES6: Proxy概念及用法
ES6: Proxy概念及用法
59 0
玩转ES6(二)-Object.defineProperty和Proxy代理
玩转ES6(二)-Object.defineProperty和Proxy代理
94 0
|
存储 JavaScript
【ES6】Set 对象
【ES6】Set 对象
86 0