Skip to content

The easiest way to overwrite other functions with additional functionality, aka decorators in python

Notifications You must be signed in to change notification settings

minmb/extendFunction.js

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

78 Commits
 
 
 
 
 
 
 
 

Repository files navigation

extendFunction.js

The easiest way to overwrite other functions with additional functionality

Example: Let's modify alert to keep a history array of all the messages we alert:

// paste extendFunction.js into your console and run these examples in your console :)

window.alertHistory = [];
// extend alert with additional functionality.
extendFunction('alert', function(args) {
  // args is an array of the arguments alert was called with
  // args[0] is the alert message.
  alertHistory.push(args[0]);
});
// Test it!
alert('a message');
console.log(alertHistory);
if (alertHistory[0] === 'a message') {
  console.warn('extendFunction worked!');
}

So extendFunction takes 2 parameters: extendFunction(theFunction, additionalFunctionality)

Now let's add " from DevinRhode2" to every alert message

extendFunction('alert', function(args, nativeAlert) {
  // the second argument here is the nativeAlert function
  // precisely, that's window.alert before it was modified
  nativeAlert(args[0] + ' from DevinRhode2')
  // because you called nativeAlert, extendFunction doesn't.
  // however, if you don't call it, then extendFunction will
  // If you don't want the original function called, then you should just overwrite the function:
  // window.alert = function alertOverride() { ... };
});

extendFunction also works for methods:

extendFunction('console.log', function(args, nativeConsoleLog) {
  // omg console.log was called!
});

But if your functions are not global like alert and console.log, then you need to do this:

localFunction = extendFunction(localFunction, function(args, originalLocalFunction) {
  // your magic here!
});

without extendFunction, you have to write this mess of code:

var oldLocalFunction = localFunction;
localFunction = function(paramA, paramB) {
 // your magic here!
 var args = Array.prototype.slice.call(arguments);
 return oldLocalFunction.apply(this, args);
};

Modify return values:

extendFunction('strangeModule.strangeMethod', function(args, prevFunc) {
  var returnValue = prevFunc.apply(this, args);
  // docs on apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

  returnValue.extraInfo = 'idk';
  return returnValue;
});

Or promises:

extendFunction('$.ajax', function(args, prevFunc) {
  var stackOnSend = new Error().stack;

  //prevFunc is the original $.ajax
  //call that and store the value to return
  var returnValue = prevFunc.apply(this, args);
  returnValue.fail(function(){
    console.error('request failed:', arguments, 'stackOnSend:', stackOnSend);
  });
  return returnValue;
});

I'm calling the original function asynchronously, but notice extendFunction is also calling it.

What's going on?

When extendFunction sees you haven't called the original function, it calls it for you - and, if you didn't return anything (i.e. undefined was returned) then extendFunction will return the value returned from the original function.

Tell extendFunction not to call the originalFunction at all:
extendFunction(fn, function(args, originalFunction, dontCallOriginal){
  dontCallOriginal();
  $.getJSON('/posts')
  .done(function(json){
    originalFunction(json);
  });
});

MIT licensed

Bitdeli Badge

About

The easiest way to overwrite other functions with additional functionality, aka decorators in python

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 100.0%