Generic interface for looping over an iterable,
and executing a provided method for each item.

@param {any} item The item over which to iterate.
@param {Function} method The callback to execute for each iterated value.
@param {any} context The optional context to pass to each callback.
@returns {any} A reference to the original item.
function forEach(item, method, context) {
    let type = getType(item);
    switch(type) {
        case types.date:
        case types.function:
        case types.object:
        case types.regexp:
            if (!item[Symbol.iterator]) {
                for (let [key, value] of _entries(item)) {
                    if (item.hasOwnProperty(key))
                        method.call(context, value, key, item);
                }
            }
            else { // shenanigans
                for (let value of item) {
                    // do we want to check if value is array, and spread it across value/key?
                    method.call(context, value, undefined, item);
                }
            }
            break;
        case types.arguments:
        case types.array:
            for (let i = 0; i < item.length; i++)
                method.call(context, item[i], i, item);
            break;
        case types.map:
            for (let [key, value] of item)
                method.call(context, value, key, item);
            break;
        case types.set:
            for (let value of item) // treat keys and values as equivalent for sets
                method.call(context, value, value, item);
            break;
        default:
            // if unknown type, then check for Symbol.iterator
            if (item[Symbol.iterator]) {
                for (let value of item[Symbol.iterator]())
                    method.call(context, value, undefined, item);
            }
            else if (!typeset.has(type) && type && type.constructor) {
                for (let [ key, value ] of _entries(item)) {
                    if (item.hasOwnProperty(key)) // necessary with _entries?
                        method.call(context, value, key, item);
                }
            }
            break;
    }
    return item;
}