Home > Web Front-end > Vue.js > It's okay if you don't know Vue, but you must know how to use Proxy!

It's okay if you don't know Vue, but you must know how to use Proxy!

藏色散人
Release: 2023-04-14 17:23:30
forward
1727 people have browsed it

I had the idea of ​​writing this article a few months ago, but when I thought of this knowledge point, VueJs is used a lot, and I am a React developer. Or, if I were asked to choose another framework, I might be more inclined to angular, but recently I was learning NestJs and found that Reflect is widely used at the bottom, as follows:

Its okay if you dont know Vue, but you must know how to use Proxy!

##Okay, here I am explaining why I wrote this article today. This article will be based on

Object -> Proxy -> Reflect will be explained in the order, learn it quickly!

Object

In

ES5, we You can define an object and perform operations on it (add or search), as shown in the following code:

const moment = {
  age: 18,
  address: "西安",
};

moment["hobby"] = "basketball";
moment.hight = 1.59;

console.log(moment.age); // 18
Copy after login

So if we want to monitor the object, we hope to be able to monitor the properties in this object. In the process of setting or getting, we can achieve this function through the stored attributes in

Attribute Descriptor.

Attribute descriptor

In

ES5, all attributes have attribute descriptors. The specific usage is as shown in the figure below:

Its okay if you dont know Vue, but you must know how to use Proxy!

As shown in the picture above, the property descriptor corresponding to this ordinary object property is not just a

18, it also contains three other characteristics, which are :

  • writable;
  • enumerable;
  • configurable;
When creating an ordinary house type, the property descriptor will use the default value. We can use

Object.defineProperty(...) to add a new property or modify an existing property (when the When the value of attribute Configurable is true) and set the characteristics, the details are as shown in the following code:

const moment = {
  age: 18,
  address: "西安",
};

Object.defineProperty(moment, "address", {
  value: "肇庆",
  writable: true,
  configurable: true,
  enumerable: true,
});

console.log(moment.address); // 肇庆
Copy after login

This method receives three parameters, they are:

    The object to define the attribute;
  • The name of the attribute to be defined or modified or
  • Symbol;
  • The attribute to be defined or modified Descriptor;
Getter and Setter

I have talked about so many basic things before, but I have not yet explained how to receive changes in properties. Here, property descriptor

Object.defineProperty provides two properties, they are set and get. The use of the two properties is as follows:

const moment = {
  age: 18,
  address: "西安",
};

Object.keys(moment).forEach((key) => {
  let value = moment[key];
  Object.defineProperty(moment, key, {
    get: function () {
      console.log(`监听到了对象的 ${key} 属性被访问了`);
      return value;
    },

    set: function (params) {
      console.log(`监听到了对象的 ${key} 属性被修改了`);
      value = params;
    },
  });
});

moment.age = 22;
const foo = moment.address;
Copy after login

When When we assign a value to

moment.age, we will call the method on the set attribute, and eventually the output will be The age attribute of the object has been modified.

When we get the value of

moment.address, the method on the get attribute will be called, and finally the output will be The address attribute of the object is monitored. Visited .

Although these two methods can be done, if we want to monitor richer operations, we cannot do it, such as adding properties and fading properties, using

Object.defineProperty(. ..) It can’t be done

Its okay if you dont know Vue, but you must know how to use Proxy!

The final result is as shown in the picture above. The output in the terminal corresponds to the execution of the circled code above.

Then the emergence of

Proxy solves this pain point very well.

Proxy

In

ES6, a new Proxy class has been added. This class can be seen from the name and is used to help us Create a proxy. It is a special object created by you. It encapsulates another ordinary object or blocks in front of this ordinary object. For example, if you want to modify an object, it mainly has the following flow chart:

Its okay if you dont know Vue, but you must know how to use Proxy!

It is like a level that intercepts your operations.

The basic usage of this class is as follows:

const moment = {
  age: 18,
  address: "西安",
};

const proxy = new Proxy(moment, {});

console.log(proxy); // { age: 18, address: '西安' }
Copy after login

You will find that it returns the same object, but the memory address is different, so the value returned through strict equality comparison is

false.

Peoxy’s 13 types of capturers

Peoxy There are 13 capturers in total, but there are only a few commonly used ones. Here is a full explanation of them. You can check them out for details. MDN official website

Without further ado, let’s go directly to the code:

const moment = {
  age: 18,
  address: "西安",
};

function foo(x, y) {
  return x + y;
}

const proxy = new Proxy(moment, {
  has: function (target, prop) {
    console.log(`使用 in 访问了 ${prop} 是否存在于 moment 对象`);
  },
  get: function (target, property, receiver) {
    console.log(`通过读取 moment 对象中的 ${property} 属性`);
  },
  set: function (target, property, value, receiver) {
    console.log(`通过设置 moment 对象中的 ${property} 属性为 ${value}`);
  },
});

const fProxy = new Proxy(foo, {
  apply: function (target, _, params) {
    return target(...params) * 10;
  },
  construct: function (target, argumentsList, newTarget) {
    console.log(target); // [Function: foo]
    console.log(argumentsList); // [ 1, 2 ]
    console.log(newTarget); // [Function: foo]
    return {};
  },
});

"age" in proxy; // 使用 in 访问了 age 是否存在于 moment 对象
proxy.age; // 通过读取 moment 对象中的 age 属性
proxy.address = "肇庆"; // 通过设置 moment 对象中的 address 属性为 肇庆

console.log(foo(1, 2)); // 3
console.log(fProxy(1, 2)); // 30

new fProxy(1, 2);
Copy after login

In the above code,

target === moment and receiver === proxy all return true, which means target corresponds to the object to be modified, and receiver is Proxy Or an object that inherits Proxy.

操作 Proxy 的同时会修改 moment 对象。

可取消代理

普通对象总是陷入到目标对象,并且在创建之后不能改变,只要还保持着对这个代理的引用,代理的机制就将维持下去。

但是可能会存在这样的情况,比如你想要创建一个在你想要停止它作为代理时便可被停用的代理,解决的方案是创建可取消代理,具体代码如下所示:

const moment = {
  age: 18,
  address: "西安",
};

const { proxy, revoke } = Proxy.revocable(moment, {
  get: function (target, key, receiver) {
    console.log("get 捕获器");
  },
});

proxy.address;
revoke();
proxy.address;
Copy after login

最终的输出如下图所示:

Its okay if you dont know Vue, but you must know how to use Proxy!

一旦可取消代理被取消,任何对他的访问都会抛出 TypeError 错误。

Proxy的问题与不足

尽管现在 Proxy 已经做得很好了,但是在某些情况下,代理也不能与现在的 ECMAScript 机制很好地协同。

Proxy中的this

Peoxy 潜在的一个问题来源是 this 值,我们知道方法中的 this 通常执行调用这个方法的对象,具体代码如下所示:

const target = {
  moment() {
    return this === proxy;
  },
};

const proxy = new Proxy(target, {});

console.log(target.moment()); // false
console.log(proxy.moment()); // true
Copy after login

按照正常的理解这是没有问题的调用 Proxy 上的任何方法,而这个方法进而又会调用另一个方法,实际上都会调用 Proxy 内部的方法,这是符合预期的行为,但是,如果目标对象依赖于对象表示,那就可能碰到意料之外的问题。

举个例子:

const wm = new WeakMap();

class User {
  constructor(userId) {
    wm.set(this, userId);
  }

  set id(userId) {
    wm.set(this, userId);
  }
  get id() {
    return wm.get(this);
  }
}
Copy after login

由于这个实现依赖 User 实例的对象标识,在这个实例被代理的情况下就会出现问题:

const user = new User(1);
console.log(user.id); // 1

const proxy = new Proxy(user, {});
console.log(proxy.id); // undefined
Copy after login

这是因为 User 实例一开始使用目标对象作为 WeakMap 的键,代理对象却尝试从自身取得这个实例,要解决这个问题,就需要重新设置代理,把代理 User 实例改为代理 User 类本身,之后再创建代理的实例就会创建代理实例作为 WeakMap 的键了:

const UserProcess = new Proxy(User, {});
const proxy = new UserProcess(1);
console.log(proxy.id); // 1
Copy after login

Proxy与内部槽位

代理与内置引用类型的实例通常可以很好地协同,但有些 ECMAScript 内置类型可能会依赖代理无法控制的机制,结果导致在代理上调用某些方法会出错,具体代码如下所示:

const target = new Date();

const proxy = new Proxy(target, {});

console.log(proxy instanceof Date); // true
proxy.getDate(); // TypeError: this is not a Date object.
Copy after login

在上面的代码中,根据 ECMAScript 规范,Date 类型方法的执行依赖 this 值上的内部曹伟 [[NumberDate]],代理对象上不存在这个内部槽位,而且这个内部槽位的值也不能通过普通的 get()set() 操作访问到,于是代理拦截后本应该转发给目标对象的方法会抛出 TypeRrror 的错误。

这篇文章到此结束,下一篇将会详细讲解 Reflect,敬请期待。

The above is the detailed content of It's okay if you don't know Vue, but you must know how to use Proxy!. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
vue
source:juejin.im
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template