认识 Proxy()

ProxyES6新增的构造函数,主要目的是给对象中间增加了一层代理(拦截)。

形象的比喻:Proxy就是明星的经纪人,如果你想和明星谈业务必须通过经纪人来操作

  1. var proxy = new Proxy();

ProxyObject.defineProperty()劫持数据有点类似,但又有区别:

  • Object.defineProperty()主要劫持数据,给对象进行拓展,对属性进行设置。
  • Proxy返回一个代理对象,并不是数据劫持,通过处理目标对象后返回一个代理对象,通过操作代理对象中途可以做一些额外的操作,然后再操作实际对象

总结:Proxy的核心是怎么处理属性,defineProperty()方法的核心是怎么定义属性。

Proxy接收两个参数:

  1. target要处理的对象
  2. handler处理程序对象

    handler内部有非常多的方法,本文只简单的介绍setget方法(相关链接

  1. var obj = {
  2. a: 1,
  3. b: 2
  4. };
  5. var proxy = new Proxy(obj, {
  6. // get() 有两个参数,目标对象和属性值
  7. get(target, prop) {
  8. console.log("This is property value " + target[prop]);
  9. return target[prop];
  10. },
  11. // set 有三个参数,目标对象、属性值和新值
  12. set(target, prop, newVal) {
  13. target[prop] = newVal;
  14. },
  15. });
  16. console.log(obj); // {a:1, b:2}
  17. console.log(proxy); // Proxy{a:1, b:2}
  18. console.log(proxy.a);
  19. // 访问属性 a,打印以下内容:
  20. // This is property value 1
  21. // 1
  22. // 设置属性 a
  23. proxy.b = 3;
  24. console.log(obj); // {a: 1, b: 3}
  25. console.log(proxy); // Proxy {a: 1, b: 3}

Proxy还可以处理其他的数据类型。
1、处理Array

  1. var arr = [
  2. { name: "小明", age: 18 },
  3. { name: "小红", age: 19 },
  4. { name: "小王", age: 20 },
  5. ];
  6. var persons = new Proxy(arr, {
  7. get(target, prop) {
  8. return target[prop];
  9. },
  10. set(target, prop, newVal) {
  11. target[prop] = newVal;
  12. },
  13. });
  14. console.log(persons[0]); // {name: '小明', age: 18}
  15. persons[0] = { name: "小张", age: 33 };
  16. console.log(persons); // Proxy {0: {…}, 1: {…}, 2: {…}}
  17. console.log(arr); // [{"name":"小张","age":33},{"name":"小红","age":19},{"name":"小王","age":20}]

2、处理函数

  1. var fn = function () {
  2. console.log("I am a function.");
  3. };
  4. fn.a = 123;
  5. var newFn = new Proxy(fn, {
  6. get(target, prop) {
  7. return target[prop];
  8. },
  9. set() {},
  10. });
  11. console.log(newFn); // Proxy {a: 123, length: 0, name: 'fn', arguments: null, caller: null, …}
  12. console.log(newFn.a) // 123

Proxy() VS defineProperty()

Proxy()的内部处理对象方法去操作target对象 (调用proxy的方法)的时候实际操作的仍然是target对象的方法,handler内的方法可以重写target内任何方法,因此来达到代理拦截的目的。

Object.defineProperty()Proxy()都可以达到拦截数据的目的
但是Object.defineProperty()原则本身是给对象定义属性用的,所以当Arraypushpop等方法是无法触发setter机制的,改变数组长度、用数组的下标设置值的时候可以触发。

那么vue2.x是怎么用Object.defineProperty()做的?
vue2.x是把数组相关方法全部重写,所以才导致大量的代码显得非常臃肿。
为什么vue2没有使用Proxy()?
因为ES6当时兼容不太好,而在现在ES6大量使用,所以vue3Proxy()重写了!

Proxy()没有这个问题,它是通过代理去操作原始数据,而defineProperty()是对原对象操作的时候进行拦截。

Reflect

Reflect是一个对象,可以用于操作目标对象的行为,它是定义的内置对象,是方法集合的容器。
ReflectObject类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与Proxy是对应的。
image.png

举例 🌰:

  1. var obj = { a: 1, b: 2 };
  2. var proxy = new Proxy(obj, {
  3. get: function (target, prop) {
  4. // return target[prop];
  5. // 用 Reflect 代替
  6. return Reflect.get(target, prop);
  7. },
  8. set: function (target, prop, newVal) {
  9. const isOk = Reflect.set(target, prop, newVal);
  10. if (isOk) {
  11. console.log("SET successfully");
  12. }
  13. },
  14. });
  15. proxy.c = 3;
  16. console.log(proxy);

:::danger Reflect的好处
JS中好多方法都存在Object.prototype.constructor(因为都是静态方法)
Reflect相当于一个的方法容器,ECMA规定未来很有很多方法都放到Reflect 上而不是Object
JSObject的定义非常的混乱,object是广义的对象(一切皆对象),Object是狭义的对象
Object存在很多共用的方法,这样很多时候都觉得不太合理,这个时候就产生了Reflect来存储方
ReflectES6的全局的内置对象 :::