23 December, 2005

Transmitting arguments from a function to another

Lately, I was wondering how one could call a function from within another function and passing the arguments without knowing them. I point this out because it is very tricky to debug such a thing and Javascript already has the perfect hack to do that!
Try the following :

function test() {
return arguments.length;
}
test(1,2,3);

It returns 3 as espected.
Now try the call from within another function like this :

function test_in() {
test(arguments);
}
test_in(1,2,3);

It returns 1! Surprised ?
As arguments is just a special Array, it is transmitted to the test function as is.
So the test function receives only one argument which length is 3.
I have come up with the solution at the mozilla developer center.
The reserved words 'call' and 'apply' allow you to call a function in a different context than the function context. Using 'call', you give the context and the arguments, but using apply, you give the context and an array of arguments that becomes the arguments object of the called function! And that is just what we wanted.
Doing this :

function test_in() {
test.call(this, arguments);
}
test_in(1,2,3);

It doesn't solve the problem, but doing that :

function test_in() {
test.apply(this, arguments);
}
test_in(1,2,3);

It returns 3 as espected. Here is how javascript itself solves the nested blind call!

21 December, 2005

IE memory leak

Several articles have been published about the IE memory leak. One has come to the conclusion that the leak appear when two objects from different worlds (DOM vs Javascript) refer to each other. Here is an example :

myDom = document.createElement('DIV'); //DOM world
myJs = 'foo'; //JS world
myJs.dom = myDom; //First reference
myDom.js = myJs; //Second reference, creating a cycling reference

If you have this code in your page, you will see the corresponding iexplore.exe instance in your task manager increasing memory each time you reload . Here is the leak !

I have tried two things to avoid the leak, one was successfull.
The first thing I tried was to delete the reference from the Js object to the Dom object, writing this :

myJs.dom = null;

It doesn't work! So I decided to delete the reference from the Dom object to the Js Object :

myDom.js = null; // or myJs.dom.js = null;

And that worked. No more memory leak.
In conclusion, I have made up a reference cleaner which would delete Dom reference to Js objects before the page unload. That object is part of the Util class and is defined as follow :

Util.collector = new Array();
Util.collector.register = function(object) {
this.push(object);
}
Util.collector.empty = function() {
for (var i=0; i < Util.collector.length; i++)
Util.collector[i].dom.js = null;
}

each time you create a Js object that will refer to a Dom object, you register it to the collector by calling

Util.collector.register( myJs );

and somewhere in your code, you add :

window.onunload = function() { Util.collector.empty(); }