How to create an arbitrary object at runtime?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steve Neill

    How to create an arbitrary object at runtime?

    Can anyone suggest how to create an arbitrary object at runtime
    WITHOUT using the deprecated eval() function. The eval() method works
    ok (see below), but is not ideal.

    function Client() { }
    Client.prototyp e.fullname = "John Smith";
    var s = "Client";
    eval("var o = new " + s + "();");
    alert(o.fullnam e);

    Note: I want the type name of the object to be represented as a string
    (in this case "Client" -- this is a non-negotiable requirement).


    I also tried the following (which appears to fail):

    function Client() { }
    Client.prototyp e.fullname = "John Smith";
    var s = "Client";
    var o = new Object();
    o.construct = s;
    alert(o.fullnam e);


    eval() is handy but not future-proof, so any suggestions would be
    welcome.

    Kind regards,
    Steve
  • Martin Honnen

    #2
    Re: How to create an arbitrary object at runtime?



    Steve Neill wrote:
    [color=blue]
    > Can anyone suggest how to create an arbitrary object at runtime
    > WITHOUT using the deprecated eval() function. The eval() method works
    > ok (see below), but is not ideal.[/color]

    eval is not deprecated, it is certainly part of a dynamic scripting
    language like JavaScript.
    [color=blue]
    >
    > function Client() { }
    > Client.prototyp e.fullname = "John Smith";
    > var s = "Client";
    > eval("var o = new " + s + "();");
    > alert(o.fullnam e);
    >
    > Note: I want the type name of the object to be represented as a string
    > (in this case "Client" -- this is a non-negotiable requirement).
    >
    >
    > I also tried the following (which appears to fail):
    >
    > function Client() { }
    > Client.prototyp e.fullname = "John Smith";
    > var s = "Client";[/color]

    var o = new this[s]();

    should do in browsers (as long as your functions like Client are global
    functions and not nested).

    --

    Martin Honnen

    Comment

    • Jim Ley

      #3
      Re: How to create an arbitrary object at runtime?

      On 20 Oct 2004 09:46:53 -0700, sneill@mxlogic. com (Steve Neill) wrote:
      [color=blue]
      >var s = "Client";
      >eval("var o = new " + s + "();");[/color]

      o=new window[s][color=blue]
      >alert(o.fullna me);[/color]

      It's a good idea to read the FAQ and the FAQ notes, there's a lot of
      good stuff there.

      Jim.

      Comment

      • Richard Cornford

        #4
        Re: How to create an arbitrary object at runtime?

        Steve Neill wrote:[color=blue]
        > Can anyone suggest how to create an arbitrary object at
        > runtime WITHOUT using the deprecated eval() function. The
        > eval() method works ok (see below), but is not ideal.[/color]

        eval is deprecated as a method of objects, and as JScript never
        implemented it as such it was never really viable to use that method
        (though it still has not been removed from Mozilla/Gecko browsers). eval
        is un-deprecated in the current ECMA 262 standard (3rd edition) and
        should be available in all implementations (however, ECMAScript 'Compact
        Profile' (ECMA 327) are allowed to implement eval such that it just
        throws exceptions whenever it is called).

        There are better reasons for not using eval, such as not really needing
        to in this context.
        [color=blue]
        > function Client() { }
        > Client.prototyp e.fullname = "John Smith";
        > var s = "Client";
        > eval("var o = new " + s + "();");[/color]

        On the other hand, the above eval use can be re-arranged so that all of
        the string concatenation can be avoided:-

        var o = new (eval(s))();

        - allowing for the much more flexible use of arguments with the
        constructor identified by the string value of - s -. it should also
        execute faster that way, but not nearly as fast as it would if - eval -
        was not used at all.

        (looking at the production rules for the - new - operator, I suspect
        that parenthesising the function call is required to turn the
        CallExpression - eval(s) - into a PrimaryExpressi on. PrimaryExpressi ons
        being allowed as operands for - new -, while CallExpressions are not)
        [color=blue]
        > alert(o.fullnam e);
        >
        > Note: I want the type name of the object to be represented
        > as a string (in this case "Client" -- this is a
        > non-negotiable requirement).[/color]

        Don't jump to this conclusion too quickly, if you can passa the value of
        variable holding a string that is the identifier of a function
        (constructor) around could you instead pass the value of a variable
        holding a reference to that function about instead? It is quite viable
        to do:-

        function Client(){ ... }
        function Other(){ ... }

        var f1 = Client; // reference to the 'Client' function object
        var f2 = Other; // reference to the 'Other' function object

        function getNewObject( constrct ){
        return new constrct(); //Indirect and anonymous use of
        //the constructor passed as the
        //parameter - constrct.
        }

        var o1 = getNewObject( f1 ); //Client instance
        var o2 = getNewObject( f2 ); //Other instance

        var o3 = new f1(); //another Client instance
        var o4 = new f2(); //another Other instance

        - or something more indirect. Passing references to functions about is
        not necessarily different to passing strings about.
        [color=blue]
        > I also tried the following (which appears to fail):
        >
        > function Client() { }
        > Client.prototyp e.fullname = "John Smith";
        > var s = "Client";
        > var o = new Object();
        > o.construct = s;
        > alert(o.fullnam e);[/color]

        I wouldn't say it failed, it is clear that the outcome programmed in the
        code is the alerting of an undefined value, and that is what it did
        (successfully), didn't it?
        [color=blue]
        > eval() is handy but not future-proof, so any suggestions
        > would be welcome.[/color]

        There probably is not future-proofing issue here. There is a code design
        issue as any use of - eval - is almost certainly indicative of
        ill-conceived design (as there are so very few circumstances where its
        use is appropriate/required, especially given how dynamic javascript is
        to start with).

        In javascript all functions are objects and all functions may be
        constructors (they can all be called as constructors but the ones
        explicitly returning ECMAScript native Object types will not be
        successful constructors, and most will not be useful constructors). As a
        result you can reference functions that you want to use as constructors
        in exactly the same way as you reference any objects.

        As Martin has said, if the constructor function is defined in the global
        scope it becomes a property of the global object (on a browser the
        global object is the window object), and a bracket notation property
        accessor syntax, with a reference to the global object as the
        MemberExpressio n/CallExpression to the left of the brackets, can access
        any properties of the global object based on the value of a string
        variable (or expression resulting in a string).

        In code executing in the global context, or within function bodies that
        are not being called as methods of object, the - this - keyword is a
        reference to the global object.

        var o = new this[ s ]();

        Other references to the global object are available on web browsers in
        the form of the - self - and - window - properties of the global object.

        var o = new window[ s ]();

        var o = new self[ s ](); // I don't recommend ever
        // using - self - in this context.

        Other methods of getting a reference to the global object include:
        Making your own global variable that reefers to the global object by
        executing:-

        var global = this;

        - in the global context as the page loads. This allows any code to use
        the global variable - global - to refer to the global variable. E.G.:

        var o = new global[ s ]();

        A global function could be created:-

        function getGlobal(){
        return this;
        }

        - and allow any code to call that function from any context to get a
        reference to the global object. E.G.:-

        var o = new getGlobal()[ s ]();

        A reference to the global object may also be retrieved in any context
        (including an object's method, where - this - would refer to that
        object) through the inline execution of a function expression that
        returns - this -, allowing such a value to be assigned to a variable
        local to a method without any external dependencies. E.G.:-

        AnyObject.proto type.exampleFnc = function(){
        var localGlobalRef = (function(){ret urn this;})();
        ...
        var o = new localGlobalRef[ s ]();
        }

        - Or as a rather heavyweight one-off:-

        var o = new ((function(){re turn this;})())[ s ]();

        Richard.


        Comment

        • John G Harris

          #5
          Re: How to create an arbitrary object at runtime?

          In article <25f8d8e5.04102 00846.143ff68@p osting.google.c om>, Steve Neill
          <sneill@mxlogic .com> writes[color=blue]
          >Can anyone suggest how to create an arbitrary object at runtime
          >WITHOUT using the deprecated eval() function. The eval() method works
          >ok (see below), but is not ideal.
          >
          >function Client() { }
          >Client.prototy pe.fullname = "John Smith";
          >var s = "Client";
          >eval("var o = new " + s + "();");
          >alert(o.fullna me);
          >
          >Note: I want the type name of the object to be represented as a string
          >(in this case "Client" -- this is a non-negotiable requirement).[/color]
          <snip>

          Would you be happy writing
          var o = new f[s]();

          If you would then make f (with a better name) an object whose properties
          (methods) are the constructor functions you want to use.

          John
          --
          John Harris

          Comment

          • Alexis Nikichine

            #6
            Re: How to create an arbitrary object at runtime?

            Steve Neill wrote:
            [color=blue]
            > Can anyone suggest how to create an arbitrary object at runtime
            > WITHOUT using the deprecated eval() function. The eval() method works
            > ok (see below), but is not ideal.[/color]

            As a related question: does anybody know how to create an object at
            runtime, by applying it an array of arguments ?

            I know how to forward a function call:

            function forwarder()
            {
            /* dest is the function the call is forwarded to: */
            return dest.apply(this , arguments);
            }


            but, given

            function CTor(a1, a2)
            {
            print("CTor - a1 = " + a1 + " a2 = " + a2);
            }

            How do I have my forwarder function returns a constructed CTor ? A few
            guesses, that won't work:

            return new (CTor.apply( null, arguments) ); // new fails

            return (new CTor).apply( null, arguments); // .apply fails


            The closest I could get was by using an helper function to construct my
            object in two passes.

            function constructWithAr gs( fun, args )
            {
            var tmp = new fun; // first, make an object of 'fun' constructor
            fun.apply(tmp, args); // second, 'fills' it with arguments
            return tmp;
            }

            But this requires that "new fun" won't fail, and some other constraints
            on fun.

            Any clue ?

            Alexis


            --
            Some domain is free

            Comment

            • Richard Cornford

              #7
              Re: How to create an arbitrary object at runtime?

              Alexis Nikichine wrote:[color=blue]
              > Steve Neill wrote:[/color]
              <snip>[color=blue]
              > As a related question: does anybody know how to create an
              > object at runtime, by applying it an array of arguments ?[/color]
              <snip>[color=blue]
              > The closest I could get was by using an helper function to
              > construct my object in two passes.[/color]

              That seems a reasonable approach. The problem, I assume, is that the
              constructor gets called twice and may not behave correctly when it finds
              it has no arguments on the first call.
              [color=blue]
              > function constructWithAr gs( fun, args )
              > {
              > var tmp = new fun; // first, make an object of 'fun'
              > constructor fun.apply(tmp, args); // second, 'fills' it with
              > arguments return tmp;
              > }
              >
              > But this requires that "new fun" won't fail, and some
              > other constraints on fun.[/color]

              In ECMAScript all objects are the same type, but augmented in different
              ways. The augmentation of an Object created with a constructor is the
              assigning of the function's - prototype - object to the Object's
              internal [[Prototype]] property and any additional property creation
              done by the constructor itself. Your function achieves this because
              creating the Object with - new fun - sets up the internal [[Prototype]]
              property and then using - apply - with the constructor as a function
              does the rest of the augmentation. But it cannot prevent the first call
              to the constructor without arguments from mis-configuring the object in
              a way that the second call will not correct/override.

              However, as all ECMAScript objects are the same type you should be able
              to achieve satisfactory results by using an empty constructor with the -
              new - operator, having assigned the - prototype - property of - fun - to
              that empty constructor. Thus having the internal [[Prototype]] property
              of the constructed Object assigned fun's prototype. And then use apply
              with the constructor:-

              var constructWithAr gs = (function(){
              function Dummy(){ ; }// Scope-contained, "private",
              // dummy constructor. No other code
              // needs access to this constructor.
              return (function(fun, args){
              Dummy.prototype = fun.prototype;
              var tmp = new Dummy; // Internal [[Prototype]] of new
              // object is set to fun.prototype
              // but no other properties are
              // created/changed.
              fun.apply(tmp, args); // Use constructor to create/apply
              // new properties to the Dummy instance,
              // creating an object indistinguishab le
              // form one created with - fun -.
              return tmp; // Return the new object
              })
              })();
              //^^ Inline function expression call, returning the second inner
              //function and assuaging it to the global variable - constructWithAr gs


              Richard.


              Comment

              • Lasse Reichstein Nielsen

                #8
                Re: How to create an arbitrary object at runtime?

                Alexis Nikichine <alexis.nikichi ne@somedomain.f r> writes:
                [color=blue]
                > The closest I could get was by using an helper function to construct
                > my object in two passes.
                >
                > function constructWithAr gs( fun, args )
                > {
                > var tmp = new fun; // first, make an object of 'fun' constructor
                > fun.apply(tmp, args); // second, 'fills' it with arguments
                > return tmp;
                > }
                >
                > But this requires that "new fun" won't fail, and some other
                > constraints on fun.[/color]

                It should be possible to create an object that is indistinguishab le
                from one created using the constructor, but actually using another
                constructor that you know will not fail. It will still be two-phase,
                but the first phase is under your control :).
                ---
                function newApply(constr uctor, argsArray) {
                function dummyConstructo r (){};
                dummyConstructo r.prototype = constructor.pro totype;
                var object = new dummyConstructo r();
                var sndObject = constructor.app ly(object, argsArray);
                return (typeof sndObject == "object" ? sndObject : object);
                }
                ---
                (It really implements the behavior of [[Construct]] on function
                objects as specified in ECMA 262 section 13.2.2, except using apply to
                call the function with an array of arguments).

                You can the use it as:
                ---
                function Const(x,y) {
                this.x = x;
                this.y = y;
                }
                Const.prototype .z = 42;

                var o = newApply(Const,[2,4]); // equivalent to: new Const(2,4)
                alert([o instanceof Const, o.x, o.y, o.z]); // true,2,4,42
                ---

                /L
                --
                Lasse Reichstein Nielsen - lrn@hotpop.com
                DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
                'Faith without judgement merely degrades the spirit divine.'

                Comment

                • Steve Neill

                  #9
                  Re: How to create an arbitrary object at runtime?

                  Perfect! Now that I see the solution it's so obvious!! Thanks :)

                  John G Harris <john@nospam.de mon.co.uk> wrote in message news:<THzSCBBxa rdBFwlj@jgharri s.demon.co.uk>. ..[color=blue]
                  > In article <25f8d8e5.04102 00846.143ff68@p osting.google.c om>, Steve Neill
                  > <sneill@mxlogic .com> writes[color=green]
                  > >Can anyone suggest how to create an arbitrary object at runtime
                  > >WITHOUT using the deprecated eval() function. The eval() method works
                  > >ok (see below), but is not ideal.
                  > >
                  > >function Client() { }
                  > >Client.prototy pe.fullname = "John Smith";
                  > >var s = "Client";
                  > >eval("var o = new " + s + "();");
                  > >alert(o.fullna me);
                  > >
                  > >Note: I want the type name of the object to be represented as a string
                  > >(in this case "Client" -- this is a non-negotiable requirement).[/color]
                  > <snip>
                  >
                  > Would you be happy writing
                  > var o = new f[s]();
                  >
                  > If you would then make f (with a better name) an object whose properties
                  > (methods) are the constructor functions you want to use.
                  >
                  > John[/color]

                  Comment

                  Working...