Skip to content

Instantly share code, notes, and snippets.

@wayspurrchen
Last active January 9, 2016 05:37
Show Gist options
  • Save wayspurrchen/cc7ae4d3040d95956a48 to your computer and use it in GitHub Desktop.
Save wayspurrchen/cc7ae4d3040d95956a48 to your computer and use it in GitHub Desktop.
demo code showing how AngularJS 1.6 injectors (probably) magically inject services by name
/**
* This gist shows how you can inject other functions/variables
* into a function only by name. I imagine this is probably something
* like how AngularJS 1.6 does it, but Angular relies on an internal
* list of registered modules instead of just whatever's floating
* around the namespace, which is dangerous.
**/
// Things to inject
function LoggerOne () {
this.log = function ( message ) {
console.log( 'LoggerOne says:', message );
};
}
function LoggerTwo () {
this.log = function ( message ) {
console.log( 'LoggerTwo says:', message );
};
}
// Injector func that wraps a function
function Injector( fnc ) {
// Turn the function's constructor into a string
var params = fnc.prototype.constructor.toString();
// Grab the first () associated with the function definition
var paramString = params.match(/\(.+\)/)[ 0 ];
// Strip off the outer ()'s and trim any spaces
var paramString = paramString.substring( 1, paramString.length - 1 ).trim();
// Split at the "," and turn it into a trim
var params = paramString.split(',').map( function ( param ) {
return param.trim();
} );
// fnc as first param because we will apply injectedParams
// to bind in order to pass multiple values to bind from an array,
// so we need to make sure the fnc is the context of the function
var injectedParams = [ fnc ];
for ( var i = 0; i < params.length; i++ ) {
// The VM will throw an error if we try to assign undefined in eval,
// so we need to wrap it in a trycatch.
eval(
"try {" +
"var resolvedParam = " + params[ i ] + ";" +
"} catch (ReferenceError) {" +
"resolvedParam = false;" +
"}"
);
if ( resolvedParam ) {
injectedParams.push( resolvedParam );
} else {
// If the parameter can't be found, assume the user wants
// to pass more variables to the function. (This doesn't
// account for people mistyping things to inject.)
break;
}
}
return fnc.bind.apply( fnc, injectedParams );
}
// Function to be injected with loggers, only by parameter name!
function logMessage ( LoggerOne, LoggerTwo, message ) {
var logger = new LoggerOne();
logger.log( message );
logger = new LoggerTwo();
logger.log( message );
}
// Make it happen
function doIt() {
var injectedLogMessage = Injector( logMessage );
injectedLogMessage( 'hey there' );
// Output:
// "LoggerOne says: hey there"
// "LoggerTwo says: hey there"
}
doIt();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment