There are often cross cutting concerns in your app, such as logging, security checkpoints and or maybe business validations.

This is a very simple approach of implementing method interceptors in pure javascript.

The crux: This decorates all the methods for the given object with before and after interceptions.

intercept: function(o) {
    for (let p in o) {
        if (typeof o[p] === 'function') {
            let c = o[p];
            o[p] = function() {
                MIFactory.beforeExecution(o, p);
                let r = c.call(o, arguments);
                MIFactory.afterExecution(o, p);
                return r;
            }
        }
    }
    return o;
}

method interceptor factory:

MIFactory = {
    interceptors: [],
    register: function(interceptor) {
        MIFactory.interceptors.push(interceptor);
    },
    unregister: function(interceptor) {
        var index = MIFactory.interceptors.indexOf(interceptor);
        if (index > -1) {
            MIFactory.interceptors.splice(index, 1);
        }
    },
    beforeExecution: function(o, p) {
        if (!o.__interceptors__) o.__interceptors__ = [];
        if (!o.__interceptors__[p]) o.__interceptors__[p] = [];
        for (var i = 0; i < MIFactory.interceptors.length; i++) {
            try {
                o.__interceptors__[p].push(new MIFactory.interceptors[i]());
            } catch (e) {}
        }

        for (var i = 0; i < o.__interceptors__[p].length; i++) {
            try {
                o.__interceptors__[p][i].beforeExecution(o, p);
            } catch (e) {}
        }
    },
    afterExecution: function(o, p) {
        for (var i = 0; i < o.__interceptors__[p].length; i++) {
            try {
                o.__interceptors__[p][i].afterExecution(o, p);
            } catch (e) {}
        }
    },
    intercept: function(o) {
        for (let p in o) {
            if (typeof o[p] === 'function') {
                let c = o[p];
                o[p] = function() {
                    MIFactory.beforeExecution(o, p);
                    let r = c.call(o, arguments);
                    MIFactory.afterExecution(o, p);
                    return r;
                }
            }
        }
        return o;
    }
}

This is a simple method interceptor: This just logs before and after execution of the context method.

MyInterceptor = function() {
    var time;
    this.beforeExecution = function(o, p) {
        time = (new Date()).getTime();
        Logger.log('before..' + p);
    }
    this.afterExecution = function(o, p) {
        time = (new Date()).getTime() - time;
        Logger.log('after..' + p + ' ... time taken: ' + time + ' ticks');
    }
}

You may have any number of interceptors, they all need to implement the contract

{
    function beforeExecution;
    function afterExecution;
}

This is a simple class that i need to add interceptions:

MyTestClass = function() {

    this.doMethod1 = function() {
        console.log('executing method 1');
        for (var i = 0; i < 230000; i++) {
            var x = new Date();
            var y = x.toString();
        }
        return 100;
    }

    this.doMethod2 = function() {
        console.log('executing method 2');
        for (var i = 0; i < 100000; i++) {
            var x = new Date();
            var y = x.toString();
        }
    }
}

Without modifying the class, I will prepare it for interception, by decorating it via MIFactory.

let m = MIFactory.intercept(new MyTestClass());
console.log('_________________________');
console.log('Result ' + m.doMethod1());
console.log('_________________________');
m.doMethod2();

The output is:

_________________________
executing method 1
Result 100
_________________________
executing method 2

I will register my interceptor. [MyInterceptor] and do the same execution.

MIFactory.register(MyInterceptor);

let m = MIFactory.intercept(new MyTestClass());
console.log('_________________________');
console.log('Result ' + m.doMethod1());
console.log('_________________________');
m.doMethod2();

now the results look like this.

_________________________
before..doMethod1
executing method 1
after..doMethod1 ... time taken: 654 ticks
Result 100
_________________________
before..doMethod2
executing method 2
after..doMethod2 ... time taken: 285 ticks

SHOW ME THE CODE