Using the arguments object when instantiating via constructor function

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Matt Eberts

    Using the arguments object when instantiating via constructor function

    Sorry, bad title. Anyway, is there a way to pass the arguments to an object
    instantiated via a constructor using the arguments object and have it
    expanded, so to speak, so that it doesn't appear as a single argument? I'm
    sorry, this explanation is just atrocious, but I can't think of exactly how
    to word it. Maybe an example...

    Take for instance Function.apply. It takes 1-2 arguments, the first being
    the object to use as the context, and the second being either an array or an
    instance of the arguments object which are to be the arguments for the
    function. I want to do something similar but I want to also basically use
    the new operator so that I get back an object.

    Here's a snippet of some of my code, maybe this will help:

    function Singleton()
    {
    this.construct. apply(this, arguments);
    }

    Singleton.exten d(JSClass);

    Singleton.insta nce = null;

    Singleton.getIn stance = function()
    {
    if(!this.instan ce)
    {
    //I want to be able to combine these two lines. If I just do new
    this(arguments) , then the constructor
    //thinks there is only one argument; the arguments object isn't
    expanded.
    this.instance = new this();

    this.instance.c onstruct.apply( this.instance, arguments);
    }

    return this.instance;
    }

    function Test()
    {
    this.construct. apply(this, arguments);
    }

    Test.extend(Sin gleton);

    Test.getInstanc e = function()
    {
    return Test.supers["Singleton"].getInstance.ap ply(this,
    arguments);
    };

    Test.prototype. name = null;

    Test.prototype. construct = function()
    {
    switch(argument s.length)
    {
    case 0:
    this.name = "Test";
    break;
    case 1:
    this.name = arguments[0];
    break;
    }
    };

    Anyway, I hope that despite this rather terrible explanation I've somehow
    managed to get my point across. Any help would be much appreciated.

    Thanks.

    Matt


  • Douglas Crockford

    #2
    Re: Using the arguments object when instantiating via constructor function

    > Sorry, bad title. Anyway, is there a way to pass the arguments to an object[color=blue]
    > instantiated via a constructor using the arguments object and have it
    > expanded, so to speak, so that it doesn't appear as a single argument? I'm
    > sorry, this explanation is just atrocious, but I can't think of exactly how
    > to word it. Maybe an example...
    >
    > Take for instance Function.apply. It takes 1-2 arguments, the first being
    > the object to use as the context, and the second being either an array or an
    > instance of the arguments object which are to be the arguments for the
    > function. I want to do something similar but I want to also basically use
    > the new operator so that I get back an object.[/color]
    ....[color=blue]
    > Anyway, I hope that despite this rather terrible explanation I've somehow
    > managed to get my point across. Any help would be much appreciated.[/color]

    I'm unclear on what you want to do. Can you give us a brief specification? It is
    difficult to sort through your code and try to guess what its intended effect
    is.

    Comment

    • Matt Eberts

      #3
      Re: Using the arguments object when instantiating via constructor function

      Yeah, I'm sorry, I can't think of how to say it.

      Okay, you know how with the apply() method of the Function object, you could
      essentially string together a function calls without knowing the arguments
      actually sent to the function? Something like:

      function func_1()
      {
      func_2.apply(ar guments);
      }

      function func_2(foo, bar)
      {
      //etc
      }

      ....

      function someFunction()
      {
      //blah
      func_1("bleh", 5);
      }

      I was wondering if there was essentially a way do the same kind of thing
      when creating an object via a constructor function. Something like:

      function func_1()
      {
      //If you do this, the arguments array for the constructor function has only
      one argument, and that's another
      //argument array. I want this to be expanded in a similar fashion to the
      apply() method.
      new this(arguments) ;
      }

      function TestClass()
      {
      this.blah = arguments[0];
      this.blah2 = arguments[1];
      }

      function func_2()
      {
      func_1.apply(th is, arguments);
      }

      function someFunction()
      {
      func_2("bleh", 5);
      }

      I still think I'm doing a horrid job explaining this, and I'm really sorry.
      I just can't think of how to explain it.

      Matt


      Comment

      • Laurent Bugnion, GalaSoft

        #4
        Re: Using the arguments object when instantiating via constructorfunc tion

        Hi,

        Matt Eberts wrote:
        [color=blue]
        > Sorry, bad title. Anyway, is there a way to pass the arguments to an object
        > instantiated via a constructor using the arguments object and have it
        > expanded, so to speak, so that it doesn't appear as a single argument? I'm
        > sorry, this explanation is just atrocious, but I can't think of exactly how
        > to word it. Maybe an example...
        >
        > Take for instance Function.apply. It takes 1-2 arguments, the first being
        > the object to use as the context, and the second being either an array or an
        > instance of the arguments object which are to be the arguments for the
        > function. I want to do something similar but I want to also basically use
        > the new operator so that I get back an object.[/color]

        Is this what you mean?

        function CTest()
        {
        this.m_strArg1 = "";
        if ( arguments.lengt h > 0 )
        {
        this.m_strArg1 = arguments[ 0 ];
        }

        this.m_strArg2 = "";
        if ( arguments.lengt h > 1 )
        {
        this.m_strArg2 = arguments[ 1 ];
        }
        }

        CTest.prototype .alert = function()
        {
        alert( this.m_strArg1 + "\n" + this.m_strArg2 );
        }

        var oTest1 = new CTest();
        oTest1.alert();

        var oTest2 = new CTest( "Hello" );
        oTest2.alert();

        var oTest3 = new CTest( "Hello", "World" );
        oTest3.alert();

        Laurent
        --
        Laurent Bugnion, GalaSoft
        Webdesign, Java, JavaScript: http://www.galasoft-LB.ch
        Private/Malaysia: http://mypage.bluewin.ch/lbugnion
        Support children in Calcutta: http://www.calcutta-espoir.ch

        Comment

        • Dom Leonard

          #5
          Re: Using the arguments object when instantiating via constructorfunc tion

          Matt Eberts wrote:
          [color=blue]
          > Sorry, bad title. Anyway, is there a way to pass the arguments to an object
          > instantiated via a constructor using the arguments object and have it
          > expanded, so to speak, so that it doesn't appear as a single argument? I'm
          > sorry, this explanation is just atrocious, but I can't think of exactly how
          > to word it.[/color]

          No, this is not directly possible in javascript. The new operator
          invokes both the [[Construct]] and [[Call]] properties of the
          constructor function following the "new" operator. So the line

          var bar = new Foo.apply(thisO bject, argumentsArray)

          would attempt to create a new Function.protot ype.apply object, which (in
          Mozilla at least) raises an exception because apply can not be called in
          isolation.

          Choices of solution lie between rewriting the program with simpler
          logic, adding additional logic to the constructor function - say by
          testing for magic arguments or flag variables located outside the
          execution context of the constructor - or creating a generalised
          mechanism to effectively split [[Construct]] and [[Call]] processing in
          javascript. A function to achieve the last might go:

          Function.protot ype.newApply = function (constructor, argsArray)
          { function dummy(){};
          dummy.prototype = constructor.pro totype;
          var newObj = new dummy();
          var obj = constructor.app ly(newObj, argsArray);
          if(obj && typeof obj == "object")
          return obj;
          return newObj;
          }

          The [[Call]] property of the dummy inner function is invoked, of course,
          but intentionally doesn't do anything. newApply would then be called as

          bar = Foo.newApply( argsArray);

          or even

          bar = new Foo.newApply( argsArray);

          (although this would create a new object that is immediately discarded).

          --

          Dom


          Comment

          • Dom Leonard

            #6
            Re: Using the arguments object when instantiating via constructorfunc tion

            Whoops!

            Sorry, getting tired over here... I rewrote an earlier version of
            newApply as a method of Function.protot ype and forgot to change the
            first argument into the "this" object. Code example should read:

            Function.protot ype.newApply = function (argsArray)
            { function dummy(){};
            dummy.prototype = this.prototype;
            var newObj = new dummy();
            var obj = this.apply(newO bj, argsArray);
            if(obj && typeof obj == "object")
            return obj;
            return newObj;
            }

            Tested in Mozilla only

            --

            Dom


            Comment

            • Douglas Crockford

              #7
              Re: Using the arguments object when instantiating via constructor function

              > Yeah, I'm sorry, I can't think of how to say it.[color=blue]
              >
              > Okay, you know how with the apply() method of the Function object, you could
              > essentially string together a function calls without knowing the arguments
              > actually sent to the function?
              >
              > I was wondering if there was essentially a way do the same kind of thing
              > when creating an object via a constructor function. Something like:
              >
              > function func_1()
              > {
              > //If you do this, the arguments array for the constructor function has only
              > one argument, and that's another
              > //argument array. I want this to be expanded in a similar fashion to the
              >
              > I still think I'm doing a horrid job explaining this, and I'm really sorry.
              > I just can't think of how to explain it.[/color]

              Are you asking if it is possible to wrap a Constructor with a function that
              takes an array that will be applied to the constructor?

              If so, is it

              var myObj = ConstructorWrap per([array]);

              If so, then trivially,

              function ConstructorWrap per(a) {
              return Constructor(a[0], a[1], a[2], ...);
              }

              But from your description, I'm not sure at all that that is what you want. If
              you can't describe something, how can you ever hope to implement it correctly?

              Comment

              • Matt Eberts

                #8
                Re: Using the arguments object when instantiating via constructor function

                > No, this is not directly possible in javascript. The new operator[color=blue]
                > invokes both the [[Construct]] and [[Call]] properties of the
                > constructor function following the "new" operator. So the line
                >
                > var bar = new Foo.apply(thisO bject, argumentsArray)
                >
                > would attempt to create a new Function.protot ype.apply object, which (in
                > Mozilla at least) raises an exception because apply can not be called in
                > isolation.
                >[/color]

                Okay, I kind of figured that it wouldn't. Thanks for the explanation.

                Matt


                Comment

                • Dom Leonard

                  #9
                  Re: Using the arguments object when instantiating via constructorfunc tion

                  Whoops squared!

                  After getting some sleep, I realise that the idea of calling newApply as
                  a method of a constructor function *and* preceding the call with a new
                  operator will trigger the same problem it is trying to solve, which was
                  to work around:

                  The new operator determines the object value of a following
                  constructor before calling it and supplying a "this" value set to a new
                  object. In the process, the constructor necessarily loses knowledge of
                  the object of which it itself may be a method.



                  --
                  Dom



                  Comment

                  • Douglas Crockford

                    #10
                    Re: Using the arguments object when instantiating via constructor function

                    > Whoops squared![color=blue]
                    >
                    > After getting some sleep, I realise that the idea of calling newApply as
                    > a method of a constructor function *and* preceding the call with a new
                    > operator will trigger the same problem it is trying to solve, which was
                    > to work around:
                    >
                    > The new operator determines the object value of a following
                    > constructor before calling it and supplying a "this" value set to a new
                    > object. In the process, the constructor necessarily loses knowledge of
                    > the object of which it itself may be a method.[/color]

                    Get some more sleep, man.

                    Comment

                    Working...