Chapter 3 Exercise Set 1 Solutions

  1. This can be done by storing the content of the set as the properties of an object. Adding a name is done by setting a property by that name to a value, any value. Removing a name is done by deleting this property. The in operator can be used to determine whether a certain name is part of the set.

    Note

    There are a few subtle problems with this approach, which will be discussed and solved in Object-oriented Programming. For this chapter, it works well enough.

    var set = {"Spot": true};
    // Add "White Fang" to the set
    set["White Fang"] = true;
    // Remove "Spot"
    delete set["Spot"];
    // See if "Asoka" is in the set
    alert("Asoka" in set);
    
  2. function range(upto) {
        var result = [];
        for (var i = 0; i <= upto; i++)
            result[i] = i;
        return result;
    }
    
    alert(range(4));
    

    Instead of naming the loop variable counter or current, as I have been doing so far, it is now called simply i. Using single letters, usually i, j, or k for loop variables is a widely spread habit among programmers. It has its origin mostly in laziness: We’d rather type one character than seven, and names like counter and current do not really clarify the meaning of the variable much.

    If a program uses too many meaningless single-letter variables, it can become unbelievably confusing. In my own programs, I try to only do this in a few common cases. Small loops are one of these cases. If the loop contains another loop, and that one also uses a variable named i, the inner loop will modify the variable that the outer loop is using, and everything will break. One could use j for the inner loop, but in general, when the body of a loop is big, you should come up with a variable name that has some clear meaning.

  3. var array = ["a", "b", "c d"];
    alert(array.join(" ").split(" "));
    
  4. function extractDate(paragraph) {
        function numberAt(start, length) {
            return Number(paragraph.slice(start, start + length));
        }
        return new Date(numberAt(11, 4), numberAt(8, 2) - 1,
                        numberAt(5, 2));
    }
    
    alert(extractDate("died 27-04-2006: Black Leclère"));
    

    It would work without the calls to Number, but as mentioned earlier, I prefer not to use strings as if they are numbers. The inner function was introduced to prevent having to repeat the Number and slice part three times.

    Note the - 1 for the month number. Like most people, Aunt Emily counts her months from 1, so we have to adjust the value before giving it to the Date constructor. (The day number does not have this problem, since Date objects count days in the usual human way.)

    In Regular Expressions we will see a more practical and robust way of extracting pieces from strings that have a fixed structure.

  5. function between(string, start, end) {
        var startAt = string.indexOf(start) + start.length;
        var endAt = string.indexOf(end, startAt);
        return string.slice(startAt, endAt);
    }
    alert(between("bu ] boo [ bah ] gzz", "[ ", " ]"));
    
  6. function formatDate(date) {
        function pad(number) {
            if (number < 10)
                return "0" + number;
            else
                return number;
        }
        return pad(date.getDate()) + "/" + pad(date.getMonth() + 1) +
                   "/" + date.getFullYear();
    }
    alert(formatDate(new Date(2000, 0, 1)));
    
  7. function oldestCat(data) {
        var oldest = null;
    
        for (var name in data) {
            var cat = data[name];
            if (!("death" in cat) &&
               (oldest == null || oldest.birth > cat.birth))
                oldest = cat;
        }
    
        if (oldest == null)
            return null;
        else
            return oldest.name;
    }
    
    alert(oldestCat(catData));
    

    The condition in the if statement might seem a little intimidating. It can be read as ‘only store the current cat in the variable oldest if it is not dead, and oldest is either null or a cat that was born after the current cat’.

    Note that this function returns null when there are no living cats in data. What does your solution do in that case?

  8. function range(start, end) {
        if (arguments.length < 2) {
                end = start;
                start = 0;
        }
        var result = [];
        for (var i = start; i <= end; i++)
            result.push(i);
        return result;
    }
    
    alert(range(4));
    alert(range(2, 4));
    

    The optional argument does not work precisely like the one in the add example above. When it is not given, the first argument takes the role of end, and start becomes 0.

  9. function sum(numbers) {
        var total = 0;
        for (var i = 0; i < numbers.length; i++)
            total += numbers[i];
        return total;
    }
    
    alert(sum(range(1, 10)));