2012-12-25

Two ways of clearing an array in JavaScript

Update 2012-12-27: Better example for aliasing in Sect. 1.

In a blog post, David Walsh mentions two approaches for emptying (clearing) an array. This blog post explains the pros and cons of both approaches. In order to understand them, we first need to know about aliasing.

Background: aliasing

Aliasing means that the same piece of mutable data can be accessed from several locations (variables, properties, etc.) in a program. Sometimes aliasing is useful, sometimes it is harmful. In this section we examine an example where its effects are harmful. Take the following object, fruitBasket, a data structure for fruits:
    var fruitBasket = {
        _fruits: [ 'Apple', 'Orange' ],
        getFruits: function () {
            return this._fruits;
        }
    };
Obviously, this is not very good code, but it illustrates a general risk related to aliasing: Letting a reference to an internal data structure escape to the outside. Code that uses fruitBasket might look like this:
    var thingsIHaveEaten = fruitBasket.getFruits();  // (*)
    thingsIHaveEaten.push('Cheese');
    console.log('Things I have eaten: '+thingsIHaveEaten);
At (*), thingsIHaveEaten has become an alias for fruitBasket._fruits. Thus, the outside has gained access to something that should be hidden inside fruitBasket. And after the above three lines of code have been executed, the integrity of fruitBasket has indeed been breached:
    > fruitBasket.getFruits()
    [ 'Apple', 'Orange', 'Cheese' ]
How can this be fixed? fruitBasket simply has to return a copy of this._fruits, instead of returning the original:
    var fruitBasket = {
        _fruits: [ 'Apple', 'Orange' ],
        getFruits: function () {
            return this._fruits.slice();  // shallow copy
        }
    };
We have performed a shallow copy: the copy is new, but the elements are the same.

Clearing an array

Let’s say we want to clear the array in the following variable myArray:
    var myArray = [ elem0, elem1, ... ];
First, you can replace the current value with an empty array. Second, you can set the array’s length to zero.

Replace an array with an empty array

The first way of clearing myArray works like this:
    myArray = [];
Depending on where the old value of myArray came from, this is the safer alternative, because you don’t change that value. You do create extra garbage: you don’t reuse the existing array, you create a new one. However, garbage collection is quite fast, so that it rarely matters (it also helps avoid an effect that incurs even more of a performance penality, as we shall see below).

Set the array’s length to zero

The second way of clearing myArray works like this:
    myArray.length = 0;
If the value of myArray is shared and all participants have to see the effect of clearing then this is the approach you need to take. However, JavaScript semantics dictate that, if you decrease the length of an array, all elements at the new length and above have to be deleted [1]. And that costs time (unless an engine has an optimization for the special case of setting a length to zero). Indeed, a performance test (mentioned by Kris Zyp) shows that the previous way of clearing is faster on all current JavaScript engines.

Reference

  1. Arrays in JavaScript

No comments: