Sat 5 Apr 2008
Here’s a fun bit of JavaScript inspired by Yehuda Katz’s jspec. It lets you call a function with a particular scope, making it ideal for calling functions that depend on a particular scope, but for whatever reason you don’t want to set up that scope statically.
function callWithScope(fn, context, scope) {
var fn_body = fn.toString().match(/^[^\{]*\{((.*\n*)*)\}/m)[1];
fn = new Function('__scope__', 'with(__scope__){\n' + fn_body + '\n}');
return fn.call(context, scope);
}
How might this be used? When writing a JavaScript spec, allowing the describe callback function to call it.
describe("callWithScope", function() {
it("should not retain the original function scope", function() {
...
})
})
Notice that it doesn’t appear to come from anywhere. When the callback passed to describe is given to callWithScope, the call might look something like this:
callWithScope(callback, this, {it: function(name, body) { ... }})
The describe callback function is turned into a string and turned into a new function of one argument, the scope. It makes it look something like this, though this isn’t entirely accurate:
describe("callWithScope", function(__scope__) {
with(__scope__) {
it("should not retain the original function scope", function() {
...
})
}
})
I’m using this in one project to call functions defined in some external scripts that expect certain objects and functions to be available. Also, since I can pass in my custom scope, I don’t have to do the work of ensuring that every function that needs that scope is declared within it. This allows me to abstract out a lot of shared code.
I’m sure there are a lot of uses for this I haven’t thought of. What’s yours?
July 5th, 2008 at 06.16
I’ve been trying to solve a problem with scope, and I’m wondering whether your code could help me somehow?…
// I have a function f, that I would like to overwrite
// BUT, I need to keep the scope of the original function!
glob= {}
(function(){ // namespace
var v= 1
glob.f= function(){ alert(v) } // Globally accessible function
})(); // end namespace
glob.f() // alerts 1
glob.f= function(){ alert(v) }
glob.f() // error - as t is undefined (new f is not in same scope as original func)
July 5th, 2008 at 06.23
BTW I needed a semicolon after glob= {} otherwise anon-func namespace did not work, so:
glob= {};
Cheers, if you can help