I have a Factory class that I use in JavaScript to dynamically load a class file over AJAX and then return an object. I have run into a VERY peculiar bug in the system though that throws errors in EVERY browser, but under a condition that is beyond my ability to explain.
Here is a simplified version of my Factory class (I removed a lot of type checking and error handling to cut it down to bare minimum).
function Factory(){
// This holds which files have already been loaded
var loaded=new Object();
// Returns a new object
this.getObject=function(className,methodName,methodData){
if(loadFile('class.'+className+'.js')){
// Making sure that the object name is defined
if(window[className]!=null){
// Has to be an object
if(typeof(window[className])=='function'){
// Creating a temporary object
return new window[className];
}
}
}
}
// Loads a file over AJAX
var loadFile=function(address){
// Loads as long as the file has not already been loaded
if(loaded[address]==null){
// Required for AJAX connections (without ASYNC)
var XMLHttp=new XMLHttpRequest();
XMLHttp.open('GET',address,false);
XMLHttp.send(null);
// Result based on response status
if(XMLHttp.status===200 || XMLHttp.status===304){
// Getting the contents of the script
var data=XMLHttp.responseText;
// Loading the script contents to the browser
(window.execScript || function(data){
window['eval'].call(window,data);
})(data);
// makes sure that file is loaded only once
loaded[address]=true;
}
}
}
This is what the user does:
var Factory=new Factory();
var alpha=Factory.getObject('example');
alpha.set(32);
alpha.get();
var beta=Factory.getObject('example');
beta.set(64);
alpha.get();
beta.get();
This fails, it says 'object is not a function' when the function is run for the second time (at the return new window[className];
line). I understand if I am missing something here, BUT here's the kicker:
If I prefix className
in my window[]
calls, then it works. For example, if I change my 'example'
class filename to 'test_example'
and then have these lines:
... if(window['test_'+className]!=null){ ...
... if(typeof(window['test_'+className])=='function'){ ...
... return new window['test_'+className]; ...
Then it works and both alpha and beta objects work as expected. When I refer to them purely through a variable, they fail. I tried things like className.toString() without success and even this fails:
className+''
This is really weird, I don't know where to look and what to try out anymore, does anyone know why this happens?
EDIT: Here is an example of the 'example.js' script that is being loaded:
function example(){
var myVar=16;
this.set=function(value){
myVar=value;
}
this.get=function(){
alert(myVar);
}
}
(and if I rename this to test_example() and load the functions as shown above with constructed strings, then it again works)
I figured out where the error was, which my above, cut-down version does not show. Apparently I named my new variable the same that the name of the class itself was, thus after first initialization it got overwritten.