This is the 14th day of my participation in Gwen Challenge

Decorator pattern common usage

A decorator pattern can also be called a wrapper.

Scenario: We need to change a very complex function and add some extra functionality to the function. But there’s a lot of complicated logic in this function. In general, it is best to leave the logic of internal functions alone.

Make changes and write them outside of the function. We can override this function by saving the original reference:

let a = function() {
    alert(1);
}

let _a = a;

a = function() {
    _a();
    alert(2);
}

a();
Copy the code

This is a common practice in real development, such as when we want to bind the onLoad event to the window, but we don’t know if it has been bound before. So we need to add onload to our existing onload. We use it in a lot of app lifecycles.

window.onload = function() {
    alert(1);
}

let _onload = window.onload || function() {};

window.onload = function() {
    _onload();
    alert(2);
}
Copy the code

Decorate functions with AOP

In fact, this also changes the orientation of this, so if we want to keep this from being changed, we need to bind this when we call the old function. If we wanted to implement a generic decorator, we could introduce AOP and bind the this pointer.

// Execute before the original function
Function.prototype.before = function(beforeFn) {
    let _self = this; // Save the original function reference
    return function() {
        beforeFn.apply(this.arguments);  // Execute the new function and bind this
        return _self.apply(this.arguments); // Execute the original function and return the result of the original function execution}}// execute after the original function
Function.prototype.after = function(afterFn) {
    let _self = this;
    return function() {
        let func = _self.apply(this.arguments);
        afterFn.apply(this.arguments);
        returnfunc; }}Copy the code

Let’s see what we can do with it when we wrap it like this. Again, the previous example:

window.onload = function() {
    alert(2);
}

// before the function
window.onload = (window.onload || function() {}).before(function() {
    alert(1);
});

// after the function
window.onload = (window.onload || function() {}).after(function() {
    alert(3);
    alert(4);
});
Copy the code

Using decorator mode can also transform our form submission to look cleaner and keep functions relatively clean.

// Execute before the original function
Function.prototype.before = function(beforeFn) {
    let _self = this; // Save the original function reference
    return function() {
        if(beforeFn.apply(this.arguments) = = =false) { // Execute the function based on the result returned by validataFunc
            return;
        }
        return _self.apply(this.arguments); // Execute the original function and return the result of the original function execution}}const validataFunc = function() {
    if(name.value === ' ') {
        alert('User name cannot be empty');
        return false;
    }
    if(pwd.value === ' ') {
        alert('Password cannot be empty');
        return false; }}const submitForm = function() {
    const {
        name: name.value,
        pwd: pwd.value
    }
    ajax(opts, (data) = > {
        console.log('success')},(err) = > {
        console.log('err')}); } submitForm.before(validataFunc());Copy the code

As a result, the validation function and the function that submits the form data are cleaned up and migrated more easily without affecting each other.