Last active
January 9, 2016 05:37
-
-
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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