JavaScript Iterators

by Tonio Loewald

HTML

<h1>Iter Documentation</h1>
<p>A simple library of iteration and related functions including: <ul>
    <li>compare(a, b, comparator -- defaults to obvious comparison)</li>
    <li>each(a, f) -- performs f on each element/property of a</li>
    <li>filter(a, f, match) -- returns all those elements/properties of a for which f returns match (defaults to true)</li>
    <li>repeat(iterations, f, match) -- calls f iterations times, stopping if f returns match (defaults to false)</li>
    <li>map(a, f) -- returns an array of elements/properties of a with f applied to them</li>
    <li>range(first, last) -- returns an array from first to last (inclusive)</li>
    <li>reduce(a, f) -- reduces elements/properties of a to a single value by recursively applying f to the first two elements and replacing them with the result until there's only one value left</li>
    </ul>
    where a, b are objects or arrays, f is a callback function, match* values cause the effect expected (match_and_include defaults to true, match_and_exit defaults to false).</p>

CSS

body {
    font-family: "Helvetica Neue", Helvetica, Arial, Sans-serif;
}
.pass {
    color: green;
}
.fail {
    color: red;
}
.exception {
    color: white;
    background-color: red;
    padding: 0 4px;
}

JavaScript

(function() {
    if (window.Iter) {
        return;
    }

    function compare(a, b, f) {
        var different = false,
            i;
        if (f === undefined) {
            f = function(a, b) {
                if (typeof a !== "object" || typeof b !== "object") {
                    return a === b;
                } else {
                    return compare(a, b, arguments.callee);
                }
            };
        }
        for (i in a) {
            if (typeof a[i] !== "function" && !f(a[i], b[i])) {
                different = true;
                break;
            }
        }
        if (!different) {
            for (i in b) {
                if (typeof b[i] !== "function" && !f(a[i], b[i])) {
                    different = true;
                    break;
                }
            }
        }
        return !different;
    }

    function each(a, f) {
        for (var i in a) {
            if (typeof a[i] !== "function") {
                if (f(a[i]) === false) {
                    break;
                }
            }
        }
        return a;
    }

    function filter(a, f, match) {
        var filtered = [];
        if (match === undefined) {
            match = true;
        }
        for (var i in a) {
            if (typeof a[i] !== "function" && f(a[i]) === match) {
                filtered.push(a[i]);
            }
        }
        return filtered;
    }

    function repeat(iterations, f, match_and_exit) {
        if (match_and_exit === undefined) {
            match_and_exit = false;
        }
        for (var i = 0; i < iterations; i++) {
            if (f(i) === match_and_exit) {
                break;
            }
        }
    }

    function map(a, f) {
        var results = [];
        this.each(a, function(elt) {
            results.push(f(elt));
        });
        return results;
    }

    function range(first, last) {
        var results = [];
        for (var i = first; i <= last; i++) {
           ...