Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Excerpt

Make functions "hookable" so you can pre-process their input and post-process their output...

 

Overview

The Hook API lets you turn an existing function in to a hookable function:

Code Block
themeRDark
languagejavascript
titleMake a function hookable
linenumberstrue
var myFn = function foo(a, b) {
	return a + b;
}
 
myFn.canHook; // false
 
var myHookedFn = Hook(myFn);
 
myFn.canHook; // false
myHookedFn.canHook; // myFn (typecasts to true)
 
myHookedFn.canHook.name; // "foo"
myHookedFn.canHook.length; // 2 (myFn defines 2 formal parameters)
 
myHookedFn.name; // "hooked"
myHookedFn.length; // 0 (doesn't define formal parameters)

Hooking a function is It's a bit like function.wraps(), in that the original function (eg. myFn) is now will be wrapped in a new function (eg. myHookedFn). The main difference is that once you've made a function hookable, you can add input and output hooks to it.

Input hooks

An input hook lets you alter the parameters (params) that will be sent to the inner function. The input parameters are:

  • params – an editable array of parameters that will be sent to the inner function
  • args – a read-only array of parameters that were used on the outer function
  • hooked – a reference to the outer function (get the inner function via hooked.canHook)

Continuing from the last example...

Code Block
themeRDark
languagejavascript
titleCreate an input hook to change params
firstline18
linenumberstrue
myHookedFn.onInput; // 0 (typecasts to false)
 
// catch the fish
myHookedFn.onInput = function(params, args, hooked) {
	// play with it (note: arguments is immutable)
	params[0] = 10; // a => 10
	// throw it back in the river
	return params;
}
 
myHookedFn.onInput; // 1 (typecasts to true)
 
myFn(1, 2); // 3 (1 + 2)
myHookedFn(1, 2); // returns 12 (10 + 2)

Remember to return the params array, otherwise the inner function won't be called.

Output hooks

An output hook lets you alter the functions return value. 

The parameters are:

  • result – the editable result returned by the inner function
  • params – a read-only array of parameters that will be sent to the inner function
  • args – a read-only array of parameters that were used on the outer function
  • hooked – a reference to the outer function (get the inner function via hooked.canHook)

Continuing from the last example...

Code Block
themeRDark
languagejavascript
titleCreate an output hook to change results
firstline33
linenumberstrue
myHookedFn.onOutput; // 0
 
myHookedFn.onOutput = function(result, params, args, hooked) {
	result -= 3;
	return result;
}
 
myHookedFn.onOutput; // 1
 
myHookedFn(1, 2); // 9 ((10 + 2) - 3)

Remember to return the result, otherwise the return value sent to the calling script will be undefined.

Multiple hooks

You can add any number of input/output hooks:

  • All the input hooks will run first, on a first-come first-served basis
  • The inner function will then be invoked (unless one of the input hooks aborted the invocation)
  • All the output hooks will run last, on a first-come first-served basis
  • The final result will be passed back to the calling script

Continuing from the last example...

Code Block
themeRDark
languagejavascript
titleAdd as many hooks as you want
firstline44
linenumberstrue
// add another output function, it will be invoked after previous one
myHookedFn.onOutput = function(result, params, args, hooked) {
	// params[0] == 10 due to input hook
	result += args[0]; // args[0] unaffected by alterations to params array
	return result;
}
 
myHookedFn.onOutput; // 2
 
myHookedFn(1, 2); // 10 (((10 + 2) - 3) + 1)
 
myHookedFn(-4, 5); // 8 (((10 + 5) - 3) + -4)

Aborting function invocations

You can abort a function run during an input hook by returning undefined instead of the params array.

Continuing from the last example...

Code Block
themeRDark
languagejavascript
titleTerminate function invocations
firstline57
linenumberstrue
myHookedFn.onInput = function(params, args, hooked) {
	if (args[0] < 0) {
		return void Hook; // kill the function invocation
		// note: output hooks will be skipped
	}
}
 
myHookedFn(1, 2); // 10 (((10 + 2) - 3) + 1)
 
myHookedFn(-4, 5); // undefined (invocation was aborted)

Notes

Hook(Hook); // Error

Hook(myHookedFn) === myHookedFn

Define("foo", myFn); Hook(myFn); // Error

Define("foo", Hook(myFn)); // ±1

Div
classbox
Availability
Status
colourGreen
titleStable

Requires: