Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Created July 24, 2010 00:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ELLIOTTCABLE/488236 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/488236 to your computer and use it in GitHub Desktop.
instanceEval for JavaScript
var instanceEval, origArgs
// This approach, by Tim Caswell (creationix) coerces the input function into a string, ensuring said function
// will be called with `instanceEval()`’s `this`, and then `with()`s that input function against `this` as well.
// This exposes the keys attached to the `this` you call `instanceEval()` on as variables within the input
// function.
instanceEval = function (input) {
if (typeof(input) === "function") input = "("+input+").call(this)"; return eval("with(this){"+input+"}") }
;(function(){ var first = "Bob", middle = "Johnathan", last = "Smith"
// ReferenceError: middle is not defined
try { instanceEval.call({first:"Tim", last:"Caswell"}, function(){ console.log(first+" "+middle+" "+last) }) }
catch (error) { console.error((error.type === "not_defined"?"ReferenceError":error.type)+": "+error.message) }
})()
// I take a different approach (also possibly faster at runtime of the function): I avoid `with()`, and instead
// serialize the keys from the object being `instanceEval()`ed upon into a series of variable names, and then
// pass those in as arguments to an invisible, anonymous function.
origArgs = "__origArgs",
instanceEval = function (input) { var that, variables, values
if (typeof(input) === "function") input = "("+input+").apply(this, "+origArgs+")"
values = (variables = Object.getOwnPropertyNames(that = this)).map(function(variable){return that[variable]})
variables[variables.length] = origArgs; values[values.length] = Array.prototype.slice.call(arguments, 1)
return (eval("(function("+variables.join(",")+"){return ("+input+")})").apply(this, values)) }
;(function(){ var first = "Bob", middle = "Johnathan", last = "Smith"
// ReferenceError: middle is not defined
instanceEval.call({first:"Tim", last:"Caswell"}, function(){ console.log(first+" "+middle+" "+last) })
catch (error) { console.error((error.type === "not_defined"?"ReferenceError":error.type)+": "+error.message) }
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment