Proxy in JavaScript: simples examples
A code simplification tool, proxy tends to separate the bulk of the application of the accessory.
Proxies provide a means to control access to functions and objects. This simplifies the reading of a program by relegating all controls to a proxy object when you can use the object in the simplest way possible.
A proxy is created with this statement:
var p = new Proxy(subjet, interface)
- The subject may be a variable, an object, a function.
- The interface is an object where a series of actions are defined, according to a predefined type: set, get, apply, etc ... We call these actions "traps", as in operating systems.
The proxy can then replace the object or function in every reference to that object or function. Each trap intercepts a type of access.
Code of the test:
var ptest = new Proxy({}, {})
if(ptest instanceof Object) document.write("Proxy supported!")
Get
Intercepts the reading of the properties of an object, or the returned value of a function.
var d = { "a": 1, "b": 2 }
var pget = new Proxy(
d, {
get: function(y, idx) {
return y[idx] * 10
}
}
)
pget.c = 3
for(var z in pget) {
document.write(z + ":")
document.write(pget[z])
}
Set
Intercepts the assignment of a value to a property, or the call of a function.
var d3 = { "a": 1, "b": 2 }
var pset = new Proxy(
d3, {
set: function(y, idx, value) {
y[idx] = value * 10
}
}
)
pset.c = 3
for(var z in pset) {
document.writez + ":" )
document.write(pset[z])
}
Has
Amend the list of properties of an object as seen during an access to it, so the list of available properties. It returns the boolean value true if you want the property to be accessed, or false otherwise, whatever the key is present or not in the original object.
var phas = new Proxy({}, {
has: function(target, key) {
if(key == "a") return false;
return true;
}
}
)
var phasa = ("a" in phas)
var phasb = ("b" in phas)
document.write("a in d: " + phasa)
document.write("b in d: " + phasb)
Apply
Lets call the proxy with a list of parameters. Intercepts also methods apply, call and Reflect.apply when the proxy is declared with a function.
To better understand the apply trap, it is first necessary to know the JavaScript apply method.
This method has parameters this and an array. The first parameter replaces by a designated object, the object that contains the function. If we call the function in a window, the window object will be replaced by another object. We pass null for not changing the contextual object.
The second parameter is an array that replaces the parameters of the function.
function methodDemo(a, b){
var str = "Object: " + this + "<br>";
for (var i in methodDemo.arguments) {
str += "argument: " + methodDemo.arguments[i] + "<br>";
}
return str;
}
document.write("Direct call to the function:");
document.write(methodDemo(10, 20));
document.write("Call through apply:");
document.write(methodDemo.apply(null, [ "ten", "twenty" ]));
This only works if we access the list of arguments through the arguments property. So we should include in the definition a special treatment if this method is used.
It's different with the apply trap where one additional function is defined.
It has three parameters:
- The name of the function for which a proxy is created.
- The context object when changing context. Null if the function remains in its context.
- A list of arguments that we pass to the target function when called.
Then you can use the proxy in three different ways.
- proxy(...arguments...)
These are the arguments passed to the function, separated by commas. - proxy.apply(null, [arguments])
This gives an array as argument list. - proxy.call (null, arg1, arg2, etc ...)
We give a list of arguments separated by commas.
You can add a context object parameter with the call or apply methods. The parameter is null as above when it remains in its context, and then call and apply methods are unnecessary.
var papp = new Proxy(methodDemo, {
apply: function(methodDemo, ctx, args) {
return methodDemo.apply(ctx, args)
}
})
document.write(papp(100, 200))
The arguments passed by the proxy replace the arguments of the apply method of methodDemo.
Construct
The construct trap intercepts new and Reflect.construct(). It returns an object.
The parameters are:
- The original object.
- The list of arguments for this new constructor.
- The constructor of the original object, optional.
var pconst = new Proxy(function() {}, {
construct: function(objTarget, args, oldConstructor) {
return { value : args[0] + " to anybody" }
}
})
document.write(JSON.stringify(new pconst("Hello "), null, ' '))
List of proxy traps
According to the ECMAScript 262 specification:
- apply.
- construct.
- deleteProperty.
- defineProperty.
- enumerate.
- get.
- getPrototypeOf.
- getOwnPropertyDescriptor.
- has.
- isExtensible.
- ownKeys.
- preventExtensions.
- set.
- setPrototypeOf.
Can we replace the proxies?
Example for get:
var d2 = { "a": 1, "b": 2 }
function p(x) {
return x * 10
}
d2.c = 3
for(var z in d2) {
document.write(z + ":" )
document.write(p(d2[z]))
}
The code is actually simpler without proxy. But they are obviously not made for such basic operations.
What is the real interest?
Probably not of interest as we execute simple operations. It is mainly a tool of clarification of the code, which allows to put on the background practical operation such as checks on the arguments, to focus on the application logic. The same could be said of object programming except that it also facilitates reusability.
To a lesser extent, the code developed for proxies is reusable, however, since in most cases, the proxy applies a function to an object. This function can be reused in new proxies.
Some examples of applications of proxies
- Security. Validity checks are placed on the parameters of a function or the values of an object.
- Data persistence. We add in a proxy backup function to each object that is fires when modifying its content.
- Statistics. We add statistical calculations to objects when they are concerned by the actions of users of an application.
- Contextual programming. For different processing contexts, we use different proxies. For example a context of debugging a production context. For debugging, proxies present the values of variables and allow to directly edit the content of objects.
- Mediator pattern. Proxies are mediators between objects that interact through them. We do not need to define relationships between this or that object.
- Conditional access. When accessing an object through a proxy, it is possible to block access to all users or a group at any time, by direct command or automatically according to conditions.