Deep Copy of Arrays

With jPaq and many other JavaScript libraries, it is very easy to do a shallow copy of an array. On the other hand, it isn’t as easy to do a deep copy of arrays. For this reason, I plan on replacing the Array.prototype.clone() function with the following:

Array.prototype.clone = function(doDeepCopy) {
    if(doDeepCopy) {
        var encountered = [{
            a : this,
            b : []
        }];

        var item,
            levels = [{a:this, b:encountered[0].b, i:0}],
            level = 0,
            i = 0,
            len = this.length;

        while(i < len) {
            item = levels[level].a[i];
            if(Object.prototype.toString.call(item) === "[object Array]") {
                for(var j = encountered.length - 1; j >= 0; j--) {
                    if(encountered[j].a === item) {
                        levels[level].b.push(encountered[j].b);
                        break;
                    }
                }
                if(j < 0) {
                    encountered.push(j = {
                        a : item,
                        b : []
                    });
                    levels[level].b.push(j.b);
                    levels[level].i = i + 1;
                    levels[++level] = {a:item, b:j.b, i:0};
                    i = -1;
                    len = item.length;
                }
            }
            else {
                levels[level].b.push(item);
            }

            if(++i == len && level > 0) {
                levels.pop();
                i = levels[--level].i;
                len = levels[level].a.length;
            }
        }

        return encountered[0].b;
    }
    else {
        return this.slice(0);
    }
};

The above code can be used to make deep copies of arrays. It is important to note, though, that only sub-arrays are deeply copied, not objects. The reason so much code is used is to even make it possible to make a deep copy of a recursive array structure. The following code exemplifies how to use this function:

// Create a recursive array to prove that the cloning function can handle it.
var arrOriginal = [1,2,3];
arrOriginal.push(arrOriginal);

// Make a shallow copy of the recursive array.
var arrShallowCopy = arrOriginal.clone();

// Prove that the shallow copy isn't the same as a deep copy by showing that
// arrShallowCopy contains arrOriginal.
alert("It is " + (arrShallowCopy[3] === arrOriginal)
    + " that arrShallowCopy contains arrOriginal.");

// Make a deep copy of the recursive array.
var arrDeepCopy = arrOriginal.clone(true);

// Prove that the deep copy really works by showing that the original array is
// not the fourth item in arrDeepCopy but that this new array is.
alert("It is "
    + (arrDeepCopy[3] !== arrOriginal && arrDeepCopy === arrDeepCopy[3])
    + " that arrDeepCopy contains itself and not arrOriginal.");

If you want to use this code right now, there is nothing stopping you. The code doesn’t require any library references and is fully cross-browser compatible. A JSBin example can be found here. It even works in JScript. The only thing that I ask is that you give credit where it is due. ­čśÇ

From Wildcards To Regular Expressions

There are a lot of people out there that no how to do file searches and Microsoft Word searches by using wildcard characters, but not as many people know how to work with regular expressions. That is the main reason why I added the RegExp.fromWildExp() function to jPaq. In addition, I have created an example page which dynamically generates the regular expression from the wildcard expression that you specify. Check this jPaq example out by clicking here. ┬áThe initial example shows you how to write a regular expression that matches all text that starts at the beginning of a word with a capital “J” and ends at the end of a word with a lowercase “t”. ┬áNOTE: ┬áUnlike regular expressions, wildcard expressions look to find the smallest match possible.

No jPaq.openWindow() For Now

Up until today, I was interested in writing a more object oriented version of the native window.open() function.┬á Unfortunately, I found out that there are some major incompatibility issues between browsers.┬á Let’s take this example for instance:

window.open("http://google.com/", "", "left=100,screenX=100,top=100,screenY=100,height=400");
window.open("http://google.com/", "", "left=100,screenX=100,top=100,screenY=100,width=400");

As you may have already guessed, the above code is simply supposed to open two new windows whose top, left corner is 100 pixels from both the top and left edge of the screen. The first window should have a height of 400 pixels and arbitrary width and the second should have a width of 400 pixels and arbitrary height. Ordinarily this code would work as expected, but on Google Chrome 10.0.648.204 and Mac OSX 10.6.5 the the windows end up being 22 pixels from the left and top of the screen. In addition, neither window has constrained the size of the window as I specified. After doing a little more testing to see if I could modify the values after creating the window, I realized that it may not be worth it to waste my time on this right now.

If you think you have found a solution to my problem, please let me know.