1

Lets define a dog:

function Dog() {}

Now lets define a self executing function that passes the Dog as a parameter:

(function(dogClassName) {

    var someServerSideLogicResolvesClassName = "dogClassName";
    //Iniate class name from the server side string
})(Dog);​

After some googleing I found that I should use

new window["dogClassName"]();

or

new this["dogClassName"]();

But since it's a scoped variable it doesn't exist in the global name space (no window) and this is undefined; I have no idea how to achieve this without using some sort of evaling.

Peeter
  • 9,282
  • 5
  • 36
  • 53
  • Just to clarify, the _"constructor"_ function isn't set in the global scope, right? it's more of a `(function(){ var someLocalConstructor = function(){}; (function(){var className = 'someLocalConstructor'; }())};())` situation? – Elias Van Ootegem Nov 07 '12 at 09:50
  • Yes, non of the variables are in the global namespace (I use requirejs, just simplified the code a lot to show the use-case) – Peeter Nov 07 '12 at 09:52
  • 1
    Can you add it to some kind of container object? Then use `new containerObj["dogClassName"]()`. Otherwise you need to use eval. – Esailija Nov 07 '12 at 09:53
  • Where are the references to variables kept then? – Peeter Nov 07 '12 at 09:54
  • @Peeter, the references to the variables are kept in that container object, of which you _know_ the name, just use the class-names as properties, then you can use a variable's value – Elias Van Ootegem Nov 07 '12 at 09:59
  • possible duplicate of [How can I access local scope dynamically in javascript?](http://stackoverflow.com/questions/598878/how-can-i-access-local-scope-dynamically-in-javascript) – Elias Van Ootegem Nov 07 '12 at 09:59

1 Answers1

2

Right, assuming that you're trying to access a constructor that isn't set globally, then the answer to your question is, quite simply: you can't do this. The scopes of closures are managed differently by the various engines. V8 might even GC the constructor if the returned function doesn't reference it explicitly...
There is no magic way to get a full outer scope as an object

The only solution would be to create a namespace-object:

(function()
{
    var constructors = {Constructor1: function(){},
                        Constructor2: function(){}};
    return function()
    {
        var className =getClassNameViaAjax();
        if (constructors.hasOwnProperty(className))
        {
            return new constructors[className]();
        }
        if (window[className] instanceof Function)
        {//fallback
            return new window[className]()
        }
        throw className + ' Does not exist in closure, nor in global scope';
    };
}());

Have a look at this question, it seems to me to be related, or even a duplicate.

Hesitant update, but for completeness
There is one way you can use a variable's value as reference in the scope chain, but it does require the most Evil of Evil functions: eval('new '+ className + '()'), as you can see in the specification, eval will preserve the this bindings, and reinitialize the scope chains. Except when you're using 'strict mode';
Since you're getting the constructor name from an ajax response, and eval is an easy thing to exploit, don't do this! This is a sort of an "in theory, you could..." thing.

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • I ended up going this path, but I still find it weird that there's no container/reference point for all the variables I pass into my callback. Thanks though. – Peeter Nov 07 '12 at 10:24
  • @Peeter: It can be annoying, from time to time, but the scope chains are seen as _internal cookery_, and cannot be accessed. [If you're up to it, you can read all about it here](http://www.ecma-international.org/ecma-262/5.1/#sec-10.2.1), or this unofficial [ECMA3 document](http://bclary.com/2004/11/07/#a-10.1.4) – Elias Van Ootegem Nov 07 '12 at 10:44