Proxy is a syntax added to the es2015 standard specification, and it is likely that you have only heard of it but not used it - after all, Proxy features cannot be used easily given the compatibility issues.
But now, with each browser’s update iteration, Proxy’s support is getting higher and higher.
Vue3 has replaced Object.defineProperty with Proxy for responsiveness, and mobx has been using Proxy for proxying since version 5.x.
1. The basic structure of Proxy
The basic usage of Proxy.
For example, if we want to proxy an object, we can set the get and set methods to proxy the operations of getting and setting data.
|
|
The Proxy is just a proxy, the personProxy has all the properties and methods of the person. When we get and set the name through personProxy
, there will be a corresponding log output.
And when the data is set by personProxy, the data in the original structure of the proxy will also change. If we print the person, we can see that the value of the field name has also changed to hello
.
|
|
The 2nd parameter of the Proxy, handler, has more rich methods besides setting get and set methods.
get(target, propKey, receiver)
: Read the properties of the interceptor, such as proxy.foo and proxy[‘foo’].set(target, propKey, value, receiver)
:` Set the properties of the interceptor object, such as proxy.foo = v or proxy[‘foo’] = v, returning a boolean value.has(target, propKey)
: Intercept the operation of propKey in proxy, returns a boolean value.deleteProperty(target, propKey)
: intercepts the delete proxy[propKey] operation, returns a Boolean.ownKeys(target)
: intercepts Object.getOwnPropertyNames(proxy), Object.getOwnPropertySymbols(proxy), Object.keys(proxy), for. .in loop, returning an array. This method returns the property names of all the target object’s own properties, while Object.keys() returns only the target object’s own traversable properties.getOwnPropertyDescriptor(target, propKey)
: Intercepts Object.getOwnPropertyDescriptor(proxy, propKey) and returns the description object of the property.defineProperty(target, propKey, propDesc)
: intercepts Object.defineProperty(proxy, propKey, propDesc), Object.defineProperties(proxy, propDescs). Returns a boolean value.preventExtensions(target)
: intercept Object.preventExtensions(proxy), returns a boolean.getPrototypeOf(target)
: intercept Object.getPrototypeOf(proxy), returns an object.isExtensible(target)
: intercept Object.isExtensible(proxy), returns a boolean.setPrototypeOf(target, proto)
: intercept Object.setPrototypeOf(proxy, proto), returns a boolean. If the target object is a function, then there are two additional operations that can be intercepted.apply(target, object, args)
: intercepts operations where the Proxy instance is called as a function, such as proxy(.. . args), proxy.call(object, . . args), proxy.apply(…) .construct(target, args)
: intercepts the operation of a Proxy instance called as a constructor, such as new proxy(… . args).
For example, if we delete one of the elements by delete, we can intercept this operation by using the deleteProperty()
method. We add a deleteProperty.
When the delete operation is performed.
2. Proxy and Reflect
Proxy and Reflect are inseparable. All the methods and usage in Reflect are exactly the same as Proxy.
For example, the get(), set() and deleteProperty() methods in the Proxy above operate directly on the original proxy object, but here we use Reflect
instead.
|
|
Perfect implementation of these functions can be found.
3. Proxy arrays
Instead of using Object.defineProperty
to hijack data, Vue overrides a few methods in the Array prototype chain to update data in the Vue template.
But with Proxy, you can proxy the array directly.
|
|
Now let’s manipulate the array arrProxy again after the proxy and see.
You can see that you can sense whether you are getting, deleting or modifying data. There are also some methods on the array prototype chain, such as
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
It can also be hijacked by the proxy method in the Proxy.
The special thing about the concat()
method is that it is an assignment operation and does not change the original array, so when the concat() method is called to manipulate the array, if there is no assignment operation, then only get() will intercept it.
4. Proxy functions
There is also an apply()
method in Proxy, which is to indicate the operation that is intercepted when called as a function by itself.
|
|
Execute fnProxy.
|
|
5. Some simple usage scenarios
We know that Vue3 has already rewritten the responsive system with Proxy, and mobx has also used Proxy pattern. In the foreseeable future, there will be more Proxy scenarios, so we will explain a few of them here.
5.1 Counting the context and number of times a function has been called
Here we use Proxy to proxy the function and then the context and number of times the function was called.
Now let’s proxy the getSum()
method we just used.
|
|
5.2 Implementing an anti-shake function
Based on the above function counting the number of function calls, it also adds inspiration to implement an anti-shake function for our functions.
|
|
logTimeStamp()
takes at least 300ms to execute once.
5.3 Implementing the Observer pattern
Here we implement the simplest class of mobx observer pattern.
|
|
person
is the proxy object created using the Proxy, and the App() function is executed whenever the properties in person change. This results in a simple responsive state management.
6. Proxy versus Object.defineProperty
Many of the above examples are also possible with Object.defineProperty
. So what are the advantages and disadvantages of each of these two?
6.1 Advantages and disadvantages of Object.defineProperty
The compatibility of Object.defineProperty
is arguably much better than Proxy, with support in all browsers except IE6 and IE7, which are particularly low.
However, Object.defineProperty supports many methods and is mainly property-based for interception. So in Vue2 you can only override methods in the Array prototype chain to manipulate arrays.
6.2 Advantages and disadvantages of Proxy
Proxy
is the opposite of the above. Proxy is object-based, so it can proxy more types, such as Object, Array, Function, etc.; and there are many more methods to proxy.
The disadvantage is that it is not very compatible, even if you use polyfill, it is not perfectly implemented.
7. Summary
There are many more features that Proxy can achieve, and we will continue to explore them and learn as much as possible about Proxy-based libraries, such as the source code and implementation principles of mobx5.