Extending javascript function scope

Go To StackoverFlow.com

4

Is it possible to extend dynamically javascript function scope? I tried without success the following:

function foo()
{
    var bar = 12;
    return function(x)
    {
        return eval(x);
    }
}

var e = foo();

console.log(e("bar"));           // 12
console.log(e("bar = 42;"));     // 42
console.log(e("bar"));           // 42
console.log(e("var baz = 99;")); // undefined
console.log(e("baz"));           // ReferenceError: baz is not defined

If however I remove var from the line baz = 99 then the baz variable becomes a global (this makes perfect sense to me):

...
console.log(e("baz = 99;"));     // 99
console.log(e("baz"));           // 99
console.log(baz);                // 99 (so baz is just a global)
2012-04-03 19:31
by 6502
Why would you want this, this is dirty as hel - Raynos 2012-04-03 19:32
@Raynos: Hehehe... may be, but I don't think it's horrible: I'm writing for fun a compiler targeting Javascript and to implement modules I'd like to know if using a function scope is a viable option while keeping the modules "open" (i.e. allowing adding names to a module from multiple places instead of having to define all names at once and having the module "sealed" after that - 6502 2012-04-03 19:37
Have you considered using objects instead? You can't use function scope as a container for module - Raynos 2012-04-03 19:53
@Raynos: Using an object would incur in double-lookup for every access to every function and every variable in the module: x.y requires first looking up x and then looking for y inside whatever is found by first lookup - 6502 2012-04-03 20:15
Your micro optimizing, compiles can optimise this away, accessing data through this[name] is faster and more efficient then accessing name through closure scop - Raynos 2012-04-03 20:34
@Raynos: I made some speed experiments and the results are quite incomprehensible for me. For example functions placed in prototype are the fastest in V8 (illogical) and a local function is slower than a function looked up using a local variable with var me = this idiom (also illogical: me.fibo() is faster than fibo() with both me and fibo being local vars). Moreover what is faster changes depending on the phase of the moon but consistently across my home 32-bit system and my office 64-bit system. This is the probably the price to pay to such a fast but complex implementation - 6502 2012-04-03 23:00
Did we learn the lesson of "Stop wasting your time prematurely optimizing - Raynos 2012-04-03 23:13


1

Everytime you call e("var baz = 4"), it's creating a variable on the stack of that function call, so it's not going to be available the next time you call it.

If you need to dynamically add variables to the scope, I would use Rayno's suggestions, use a map. http://jsfiddle.net/UVSrD/

function foo()
{
    var scope = {};
    return function(x)
    {
        return eval(x);
    }
}


var e = foo();

console.log(e("scope.bar = 12")); // 12
console.log(e("scope.bar")); // 12
console.log(e("scope.baz = 14")); // 14
console.log(e("scope.baz;")); // 14
// Not a global
console.log(typeof scope) // undefined
2012-04-03 20:00
by Juan Mendes
I understood why evaluating var baz = 99; was not working... the problem is that the scope I'd like to access is the outer one, not the one of the function returned by foo. Using a local object is an option but means using a double lookup for every access (first looking up scope and the looking up the variable or function) - 6502 2012-04-03 20:19
Yes, scope chain is lexical, so you can't modify it - Juan Mendes 2012-04-03 20:21
I accepted because your last comment make sense for me. Too bad there isn't a predefined lexical variable bound to the enclosing scope... may be this is intentional because using fixed-sized lexical scopes simplifies implementation or allows some optimization (I don't see many of them however, given that for example eval must be able to access all lexicals the implementation is forced to close over the entire scope for closures and not just the closed over variables) - 6502 2012-04-03 23:11


0

You're creating a closure using this code:

function foo()
{
    var bar = 12;
    return function(x)
    {
        return eval(x);
    }
}

When you pass in bar your overriding the bar variable that has already been initiated to 12. I'm not sure what your trying to accomplish, but using a closure will retain the outer functions variables.

2012-04-03 19:35
by Kevin Bowersox
Yes I know I'm creating a closure and the second eval is modifying a captured variable. The question is if it's possible to add more "captured variables" and local functions later or not - 6502 2012-04-03 19:40


0

Eval will run in the scope of wherever it is called. The behavior you are seeing is because on this line:

console.log(e("var baz = 99;")); // undefined

you create a var baz = 99 in the local scope of the returned function. The return value of var name = value; isn't anything, you you get undefined. when you subsequently call

console.log(e("baz"));           // ReferenceError: baz is not defined

you return a new function, where baz hasn't been defined.

This is kinda cool: http://www.bennadel.com/blog/1926-Exploring-Javascript-s-eval-Capabilities-And-Closure-Scoping.htm

2012-04-03 19:54
by Adam Shiemke
Indeed when doing that experiment I later understood why evaluating var baz doesn't work. My question is if it's possible to escape one level and get to the containing scope - 6502 2012-04-03 20:09
I dont' think this is possible because that involves modifying the scope two levels up. As far as I know, there is no way to directly effect the scope. You could create a new object and return that, but I don't believe you can directly change a scope once it has been created - Adam Shiemke 2012-04-03 20:45
Ads