Proxy and its advantages

Translation: Liu Xiaoxi

Original Link: https://devinduct.com/blogpos...

What is Proxy

Typically, when it comes to the JavaScript language, we are talking about new features offered by the ES6 standard, and this article is no exception.We'll discuss JavaScript proxies and their roles, but before we dive into them, let's first look at what Proxy is defined.

The definition on MDN is that a proxy object is a custom behavior used to define basic operations (for example, property lookup, assignment, enumeration, function call, etc.).

In other words, we can say that a proxy object is a wrapper for our target object, in which we can manipulate its properties and prevent direct access to it.You may find it difficult to apply them to actual code, and I encourage you to read this concept carefully, which may change your point of view.

term

handler

Placeholder object containing traps.

traps

Provides access to properties.This is similar to the concept of a capturer in an operating system.

target

Object for agent virtualization.(Actual objects wrapped and manipulated by proxy objects)

In this article, I'll provide simple use cases for get and set traps, considering that in the end, we'll see how to use them and include more complex functionality, such as API s.

Grammar and Use Cases

let p = new Proxy(target, handler);

A proxy object is created by passing the target and handler to the Proxy constructor.Now let's see how to use it.To see the benefits of Proxy more clearly, first, we need to write some code without it.

Imagine that we have a user object with several attributes. If attributes exist, we want to print user information. If they don't exist, we throw an exception.When the proxy object is not used, the code that determines whether the attribute value exists is also placed in the function that printUser prints the user information (which is not what we want), as shown in demo below:

let user = {
    name: 'John',
    surname: 'Doe'
};

let printUser = (property) => {
    let value = user[property];
    if (!value) {
        throw new Error(`The property [${property}] does not exist`);
    } else {
        console.log(`The user ${property} is ${value}`);
    }
}

printUser('name'); // Output:'The user name is John'
printUser('email'); // Throw error: The property [email] does not exist

get

By looking at the code above, you'll see that it's better to move conditions and exceptions elsewhere, and that the printUser focuses only on the actual logic of displaying user information.This is where we can use proxy objects. Let's update this example.

let user = {
    name: 'John',
    surname: 'Doe'
};

let proxy = new Proxy(user, {
    get(target, property) {
        let value = target[property];
        if (!value) {
            throw new Error(`The property [${property}] does not exist`);
        }
        return value;
    }
});

let printUser = (property) => {
    console.log(`The user ${property} is ${proxy[property]}`);
};

printUser('name'); // Output:'The user name is John'
printUser('email'); // Throw error: The property [email] does not exist

In the example above, we wrapped the user object and set a get method.This method acts as an interceptor, checking the attribute value before returning it, and throwing an exception if it does not exist.

The output is the same as the first case, but at this point the printUser function focuses on logic and only processes messages.

set

Another example where proxies might be useful is attribute value validation.In this case, we need to use the set method and validate it.This is a useful hook, for example, when we need to ensure the target type.Let's look at the actual use:

let user = new Proxy({}, {
    set(target, property, value) {
        if (property === 'name' && Object.prototype.toString.call(value) !== '[object String]') { // Make sure it is a string type
            throw new Error(`The value for [${property}] must be a string`);
        };
        target[property] = value;
    }
});

user.name = 1; // Throw error: The value for [name] must be a string

These are fairly simple use cases, and proxy can be used in the following scenarios:

  • Format
  • Value and type corrections
  • Data Binding
  • debugging
  • ...

Now is the time to create a more complex use case.

API with proxy - more complex example

By using the knowledge in simple use cases, we can create an API wrapper for use in our applications.Currently only get and post requests are supported, but it can be easily extended.The code is shown below.

const api = new Proxy({}, {
    get(target, key, context) {
        return target[key] || ['get', 'post'].reduce((acc, key) => {
            acc[key] = (config, data) => {

                if (!config && !config.url || config.url === '') throw new Error('Url cannot be empty.');
                let isPost = key === 'post';

                if (isPost && !data) throw new Error('Please provide data in JSON format when using POST request.');

                config.headers = isPost ? Object.assign(config.headers || {}, { 'content-type': 'application/json;chartset=utf8' }) :
                    config.headers;

                return new Promise((resolve, reject) => {
                    let xhr = new XMLHttpRequest();
                    xhr.open(key, config.url);
                    if (config.headers) {
                        Object.keys(config.headers).forEach((header) => {
                            xhr.setRequestHeader(header, config.headers[header]);
                        });
                    }
                    xhr.onload = () => (xhr.status === 200 ? resolve : reject)(xhr);
                    xhr.onerror = () => reject(xhr);
                    xhr.send(isPost ? JSON.stringify(data) : null);
                });
            };
            return acc;
        }, target)[key];
    },
    set() {
        throw new Error('API methods are readonly');
    },
    deleteProperty() {
        throw new Error('API methods cannot be deleted!');
    }
});

Let's explain the simple implementation, set and deleteProperty.We added a level of protection and made sure that whenever someone accidentally or unintentionally tried to set a new value for any API property, an exception was thrown.

The deleteProperty method is called every time a property is attempted to be deleted.You can make sure that no one can delete any attributes from our proxy (that is, the API here), since we generally don't want to lose the API methods.

Gett is interesting here. It does a few things.The target is an empty object, and the get method creates all methods (such as the current get and post request) the first time an API is used. In the reduce callback, we perform the validation and checks required by the API specification based on the configuration provided.In this example, we do not allow empty URL s and publish requests without providing data.These checks can be extended and modified, but it's important that we only focus on this one place.

Reduce completes only the first API call, then skips the entire reduce process, and get only executes the default behavior and returns the property value, the API handler.Each handler returns a Promise object that is responsible for creating requests and invoking services.

Use:

api.get({
    url: 'my-url'
}).then((xhr) => {
    alert('Success');
}, (xhr) => {
    alert('Fail');
});
delete api.get; //throw new Error('API methods cannot be deleted!'); 

conclusion

Agents can come in handy when you need more control over your data.You can monitor objects and ensure correct behavior by expanding or denying access to raw data according to controlled rules.

If you like this article, please pay attention to my public number.You can express your thoughts in the comments section below.

Thank you all for taking the time to read this article. If this article gives you some help or inspiration, please don't stint on your praise and Star. You must be my greatest motivation to move forward. https://github.com/YvetteLau/...

Pay attention to Miss Sister's public name and join the communication group.

Keywords: Javascript JSON Attribute github

Added by Bismark12 on Tue, 06 Aug 2019 05:13:06 +0300