Created
July 27, 2012 21:39
-
-
Save dherman/3190598 to your computer and use it in GitHub Desktop.
Analog to Function constructor for building closures
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
(function() { | |
var hasOwnProperty = Object.prototype.hasOwnProperty; | |
var Function = hasOwnProperty.constructor; | |
function isIdentifier(s) { | |
return /[a-zA-Z_$][a-zA-Z_$0-9]*/.test(s); | |
} | |
Closure = function Closure(args, body, env) { | |
var closedVars = [], closedVals = []; | |
for (var key in env) { | |
if (!hasOwnProperty.call(env, key)) | |
continue; | |
if (!isIdentifier(key)) | |
throw new Error("invalid variable name: " + key); | |
closedVars.push(key); | |
closedVals.push(env[key]); | |
} | |
// validate the syntax of the body as a FunctionBody | |
(new Function(body)); | |
// validate the syntax of the formal parameters as FormalParameters | |
Function.apply(null, args); | |
// declare closed variables initialized from an array bound to `this` | |
var closeVars = "var " + closedVars.map(function(x, i) { | |
return x + " = this[" + i + "]"; | |
}).join(",") + ";"; | |
// return the function that closes over the variables | |
var returnClosure = "return function(" + args.join(",") + "){" + body + "};"; | |
closedVals.maker = new Function(closeVars + returnClosure); | |
return closedVals.maker(); | |
}; | |
Closure.prototype = Function.prototype; | |
})(); | |
var f = new Closure([], "return x + y", { x: 1, y: 77 }); | |
console.log(f()); // 78 | |
var g = new Closure(["z"], "return x + y + z", { x: 1, y: 77 }); | |
console.log(g(13)); // 91 |
Cool, thanks for the replies, guys.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@fitzgen: They're different operations. Yours is much more statically well-behaved; mine is much more reflective. I don't advocate using reflection except when you know for sure you need it — for example, when writing a JIT such as Shumway. Otherwise I'd advocate using a currying API like yours.
Dave