module.exports = forEach

var toString = Object.prototype.toString

function forEach(list, iterator, context) {
    if (toString.call(iterator) !== '[object Function]') {
        throw new TypeError('iterator must be a function')
    }

    var isArray = toString.call(list) === '[object Array]'
        , isString = typeof list === 'string'
        , keys = isString ? list : Object.keys(list)

    if (arguments.length < 3) {
        context = this
    }

    for (var i = 0, len = keys.length; i < len; i++) {
        var key = isString || isArray ? i : keys[i]
            , value = isString ? keys.charAt(i) : list[key]

        iterator.call(context, value, key, list)
    }
}


module.exports = forEach

var toString = Object.prototype.toString
var hasOwnProperty = Object.prototype.hasOwnProperty

function forEach(list, iterator, context) {
    if (toString.call(iterator) !== '[object Function]') {
        throw new TypeError('iterator must be a function')
    }

    if (arguments.length < 3) {
        context = this
    }
    
    if (toString.call(list) === '[object Array]')
        forEachArray(list, iterator, context)
    else if (typeof list === 'string')
        forEachString(list, iterator, context)
    else
        forEachObject(list, iterator, context)
}

function forEachArray(array, iterator, context) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (hasOwnProperty.call(array, i)) {
            iterator.call(context, array[i], i, array)
        }
    }
}

function forEachString(string, iterator, context) {
    for (var i = 0, len = string.length; i < len; i++) {
        // no such thing as a sparse string.
        iterator.call(context, string.charAt(i), i, string)
    }
}

function forEachObject(object, iterator, context) {
    for (var k in object) {
        if (hasOwnProperty.call(object, k)) {
            iterator.call(context, object[k], k, object)
        }
    }
}

remove use of Object.keys