views:

2106

answers:

3

I have a Javascript class that contains a few functions and member objects:

function MyUtils()
{
  // Member Variables (Constructor)
  var x = GetComplexData();
  var y = DoSomeInitialization();

  // Objects
  this.ParamHash = function()
  {
    // Member variables
    this.length = 0;
    this.items = new Array();

    // Constructor
    for (var i = 0; i < arguments.length; i += 2)
    {
      // Fill the items array.
      this.items[arguments[i]] = arguments[i+1];
      this.length++;
    }
  }

  // Functions
  this.DoSomething = function()
  {
    // Do something.
    // Uses the items in the ParamHash object.
    for (var i in this.ParamHash.items)
    {
      // Really do something!
    }

    // Clear the ParamHash object -- How??
  }
}

This is invoked in the following manner:

// First call - works fine.
var utils = new MyUtils();
utils.ParamHash = new utils.ParamHash("a", 1, "b", 2);
utils.DoSomething();

// Don't want to re-initialize.
// utils = new MyUtils();

// Consequent call - crashes ["Object doesn't support this action."].
utils.ParamHash = new utils.ParamHash("c", 3);
utils.DoSomething();

The problem arises from the restriction that I want to reuse the same utils object throughout the code without having to re-initialize it. Also, I want the ParamHash object to be recreated from scratch everytime I call it. However, consequent calls to the ParamHash constructor throw an error "Object doesn't support this action." At this stage, I can see that the utils.ParamHash object still contains the old values ("a", "b").

I have tried various ways to clear the ParamHash object such as setting it's items and length to null, popping items from the array. Nothing seemed to work until I used the following way (in the DoSomething() function):

this.ParamHash.items = new Array();
this.ParamHash.length = 0;

This seems wrong because what if I had a lot of member variables... would I have to reset each of them individually? So, the question is: What is the best way to reset the ParamHash object to the initial state? I'm sure hoping that there is a cleaner/more direct way. Something like :

// Doesn't work! :-(
this.ParamHash = new function() {};

EDIT: I'm looking for a cross-browser solution - One that works atleast in IE6+ and FF 2+.


Solution: Thanks to Cristoph, I was able to do it by creating a separate variable/property within MyUtils which only holds the instance of the ParamHash function.

function MyUtils()
{
  // Same ol' stuff.
  var myParamHash;
}

// First call - works fine.
var utils = new MyUtils();
utils.myParamHash = new utils.ParamHash("a", 1, "b", 2);
utils.DoSomething();

// Consequent call - works fine now.
utils.myParamHash = new utils.ParamHash("c", 3);
utils.DoSomething();
A: 

Have you tried omitting the new keyword?

utils.ParamHash = utils.ParamHash("c", 3);
Josh Stodola
I have, even though I would have been surprised if that had worked. It says "Function expected." :-(
Cerebrus
If you omit the new keyword, it doesn't create a new object. It just runs the constructor function in a global context (setting all the properties to the window object)!
Chetan Sastry
+3  A: 

This

utils.ParamHash = new utils.ParamHash("a", 1, "b", 2);

overwrites the the property which holds the ParamHash() constructor function with an instance object. You could get the constructor back via

utils.ParamHash.constructor

but the cleaner way would be to not overwrite it in the first place and use a seperate property to hold the instance.


I don't know the exact problem Cerebrus is trying to solve, so there might be valid reasons for what he's doing. But in my opinion, his solution is overly complicated. I'd do something like this:

function MyUtils() {
    this.x = getComplexData();
    this.y = doSomeInitialization();
    this.params = {};
}

MyUtils.prototype.doSomething = function() {
    for(var prop in this.params) {
        if(this.params.hasOwnProperty(prop)) {
            // do stuff
        }
    }
};

var utils = new MyUtils;
utils.params = { a : 1, b : 2 };
utils.doSomething();

The check for hasOwnProperty() is unnecessary if you can be sure that no one messed with Object.prototype.


Some additional comments:

  • in JavaScript, normally only the names of constructor functions are capitalized
  • items shouldn't be an array, but a plain object, ie this.items = {};
Christoph
Can you provide an example of how I can use the retrieved constructor (using the constructor property) to reset the object?
Cerebrus
`utils.ParamHash = utils.ParamHash.constructor` will undo the assignment, ie after that you can assign new values via `utils.ParamHash = new utils.ParamHash("c", 3, "d", 4)`
Christoph
Thank you. I have edited my question to include the final solution I used.
Cerebrus
+2  A: 

when you did this

utils.ParamHash = new utils.ParamHash("a", 1, "b", 2);

you replaced the ParamHash constructor function with an object instance. Subsequent new ParamHash() fails because utils.ParamHash is no longer a constructor function.

Try this:

var utils = new MyUtils();
utils.paramHashInstance = new utils.ParamHash("a", 1, "b", 2);
utils.DoSomething();
Chetan Sastry
Thanks, Chetan. That does not throw an error, but then the instance or the parameters are not available within the DoSomething() function which is part of the class. I need to do the reset from within the DoSomething() function.
Cerebrus
@Cerebrus: why is the instance unavailable? `for (var i in this.paramHashInstance.items)` should work fine...
Christoph
Because I neglected to create the property within the MyUtils class. I was adding the property dynamically as @Chetan's answer seemed to suggest. See my edited question.
Cerebrus