//this.IDCounter keeps track of of an index I use to
//generate unique ID's for DOM elements
//this.lookupAdLayout returns a function that I call to
//generate the correct DOM element
this.Create = function(adType) {
var factory = this.lookupAdLayout(adType);
this.ads.push(factory(this.IDCounter));
this.IDCounter++;
return this.IDCounter-1;
}
//this.ads, as you see in the above code, is an array of custom
//objects. Here I am removing the top element from that array
//and calling the method 'ClearDom' on it.
this.Remove = function() {
var piece = this.ads.pop();
piece.ClearDom();
this.IDCounter--;
}
So, did you catch the mistake? Yeah, neither did I. The problem was each time I would call remove, the array size would shrink, but ClearDom() was always being called on the last created object instead of the top-most object in the array. Here, this is what I mean:
Let's assume the array has 3 objects in it.
this.ads = [obj1, obj2, obj3];
Now, I call this.Remove:
First Time:
this.ads.length = 2
piece.ClearDom() gets called on obj3
Second Time:
this.ads.length =1
piece.ClearDom() still gets called on obj3
Third Time
this.ads.length = 0
piece.ClearDom() STILL gets called on obj3....
Still stumped? Good, so was I. The solution is ridiculously simple once you consider what this.Create() is actually doing. Here, let's break it down:
1) var factory = this.lookupAdLayout(adType); - By calling this.lookupAdLayout, I am returning an object, which in javascript is just a fancy function that looks like this: this.SomeObject = function(). The important point is that what is returned is still a function
2) this.ads.push(factory(this.IDCounter)); - This line can be a bit confusing without seeing the rest of code, but what I am doing is calling the function that was returned in the previous line of code and putting the returned value into the array. In this case, the returned value is a reference to the object I created. IDCounter is used in the constructor and doesn't relate to this problem...
OK, I've dragged it out long enough, and now it's time for the big reveal. Line one returns an object (which is just a function), and functions are passed by reference into other functions (array.push being the function, in this case)... This matters here because each time I call this.Create what I am doing is modifying the variable 'factory' and since the rest of the array only contains references, they all update to match the newly modified 'factory'.Change the second line of this.Create to
this.ads.push(new factory(this.IDCounter));
By using the 'new' keyword, we create a new instance of factory and put that instance in the array, thereby avoiding the reference problem. Like I said, a silly mistake. Hopefully this helps somebody else.