封装实现通用的forEach函数

// v1. 实现一个自己的forEach 函数
function isArrayLike(obj) {
    // 1. 先看obj有没有length属性
    var length = !!obj && ('length' in obj) && obj.length;
    var typeRes = type(obj);

    // 2. 排除掉函数和window对象, window也是有length属性的
    if (typeRes === 'function' || isWindow(obj)) {
        return false;
    }

    // 3. 开始处理结果
    return typeRes === 'array'                  // 1. 是数组类型
        || length === 0                     // 2. 长度为0(函数中的arguments参数)
        || typeof length === 'number'
        && length > 0
        && (length - 1) in obj;             // 3. length 属性是大于 0 的数字类型,并且obj[length - 1]必须存在(符合条件的类数组对象是一定存在最后一个元素的)

}


// v1. 实现一个遍历的函数
function each(obj, callback) {
    let len, i = 0;

    // 伪数组和数组类型
    if (isArrayLike(obj)) {
        len = obj.length;
        for (; i < len; i++) {
            callback(i, obj[i]);
        }
    }
    // 对象类型
    else {
        for (i in obj) {
            callback(i, obj[i]);
        }
    }

    return obj;
}


// v2. 实现终止循环的功能
function each(obj, callback) {
    let len, i = 0;
    if (isArrayLike(obj)) {
        len = obj.length;
        for (; i < len; i++) {
            // 退出循环的条件
            if (callback(i, obj[i]) === false) {
                break;
            }
        }
    }
    else {
        for (i in obj) {
            // 退出循环的条件
            if (callback(i, obj[i]) === false) {
                break;
            }
        }
    }
}

// v3. 实现this的绑定, 使用call来绑定一个this对象
function each(obj, callback) {
    let len, i = 0;
    if (isArrayLike(obj)) {
        len = obj.length;
        for (; i < len; i++) {
            // 退出循环的条件
            if (callback.call(obj[i], i, obj[i]) === false) {
                break;
            }
        }
    }
    else {
        for (i in obj) {
            // 退出循环的条件
            if (callback.call(obj[i], i, obj[i]) === false) {
                break;
            }
        }
    }
}

[!NOTE] TODO : for的性能要比封装的each函数性能好,原因是使用了call实际上是会降低性能的

results matching ""

    No results matching ""