美文网首页
Underscore源码(3)

Underscore源码(3)

作者: ____雨歇微凉 | 来源:发表于2016-12-09 23:02 被阅读16次
    // Array Functions
    // ---------------
    
    
    
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * first
     * 返回第一个元素 或者从第一个元素开始到第n个元素
     */
    // Get the first element of an array. Passing **n** will return the first N
    // values in the array. Aliased as `head` and `take`. The **guard** check
    // allows it to work with `_.map`.
    _.first = _.head = _.take = function(array, n, guard) {
        // 如果array 不存在 则返回undefined
        if (array == null) return void 0;
        // 如果n不存在,则返回第一个
        if (n == null || guard) return array[0];
        // 否则返回第1个到n  使用了_.initial(), 把后面不要的扔掉正好是需要的
        return _.initial(array, array.length - n);
    };
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * initial
     * 返回数组中除了最后一个元素外的其他全部元素。如果有n ,就把后面n个就干掉了
     * 意思就是干掉后面多少个,类似pop,只不过可以干掉多个
     */
    // Returns everything but the last entry of the array. Especially useful on
    // the arguments object. Passing **n** will return all the values in
    // the array, excluding the last N.
    _.initial = function(array, n, guard) {
        // 拆分array, 从第0个拆分到指定位置 ,n 把后面n个就干掉了
        return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
    };
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * last
     * 和first相反,返回最后一个,或者后面n个
     */
    // Get the last element of an array. Passing **n** will return the last N
    // values in the array.
    _.last = function(array, n, guard) {
        if (array == null) return void 0;
        if (n == null || guard) return array[array.length - 1];
        //  _.rest() 没有参数n则返回最后一个,否则返回length-n 到最后一个
        return _.rest(array, Math.max(0, array.length - n));
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * rest
     * 从已有数组中返回指定字符串,原生方法
     */
    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    // Especially useful on the arguments object. Passing an **n** will return
    // the rest N values in the array.
    _.rest = _.tail = _.drop = function(array, n, guard) {
        return slice.call(array, n == null || guard ? 1 : n);
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * compact
     * 返回一个除去所有false值的 array副本。
     */
    // Trim out all falsy values from an array.
    // 因为_.identity返回的就是本身,而filter返回的是所有真值,所以会返回一个除去所有false值的 array副本。
    // 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值.
    _.compact = function(array) {
        return _.filter(array, _.identity);
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * flatten
     * 将嵌套数组扁平化,如果shallow为true,则只铺平一层
     */
    // Internal implementation of a recursive `flatten` function.
    var flatten = function(input, shallow, strict, startIndex) {
        var output = [], idx = 0;
        for (var i = startIndex || 0, length = input && input.length; i < length; i++) {
            var value = input[i];
    
            // 处理如果input[i],仍然是数组的情况 , else ,直接添加
            if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
                // 扁平当前级别的数组或参数对象,使用递归,每次循环value,将里面的数组调用并平铺
                // flatten current level of array or arguments object
                if (!shallow) value = flatten(value, shallow, strict);
                var j = 0, len = value.length;
                output.length += len;
    
                // index++ 每次添加一个子集j++的元素
                // 循环子元素,把每一个都添加到父集
                while (j < len) {
                    output[idx++] = value[j++];
                }
            } else if (!strict) {
                output[idx++] = value;
            }
        }
        return output;
    };
    
    // Flatten out an array, either recursively (by default), or just one level.
    _.flatten = function(array, shallow) {
        // 这里第三个参数是为了兼容其他的函数,
        return flatten(array, shallow, false);
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * without
     * 返回第一个数组不包含后面参数的值
     * 和difference差不多,只不过把后面的数组变成了参数
     */
    // Return a version of the array that does not contain the specified value(s).
    _.without = function(array) {
        // _.difference(array1,array2) 返回array1不存在array2中的值。
        // slice.call(arguments, 1), -> 返回所有参数除去第一个之后的一个数组
        return _.difference(array, slice.call(arguments, 1));
    };
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * uniq & unique
     * 去重
     */
    // Produce a duplicate-free version of the array. If the array has already
    // been sorted, you have the option of using a faster algorithm.
    // Aliased as `unique`.
    _.uniq = _.unique = function(array, isSorted, iteratee, context) {
        if (array == null) return [];
        // 第二个值必须是布尔值,否则为false,也就是不需要后面自定义排序方法
        if (!_.isBoolean(isSorted)) {
            context = iteratee;
            iteratee = isSorted;
            isSorted = false;
        }
        // 这是处理一个对象的方法,获取对比的属性
        if (iteratee != null) iteratee = cb(iteratee, context);
        var result = [];
        var seen = [];
        // 循环array中的每一项
        for (var i = 0, length = array.length; i < length; i++) {
            // 获取每一项的值,与比较的方式
            var value = array[i],
                computed = iteratee ? iteratee(value, i, array) : value;
            // 如果需要自定义处理,则isSorted为true
            if (isSorted) {
                // 如果i = 0,则 !i = true
                // 如果后面一个值不等于前面一个值,则push,因为已经排序,所以数组类似[1, 1, 3, 5, 5, 6, 6, 
    

    6, 7]
    // 所以只要后一个不同于前一个,就push否则跳过就好
    if (!i || seen !== computed) result.push(value);
    seen = computed;
    } else if (iteratee) {
    // 是否有条件判断语句
    if (!.contains(seen, computed)) {
    seen.push(computed);
    result.push(value);
    }
    // 比较数组
    .contains(),会返回一个是否包含第二个参数的布尔值
    // 如果不包含,则push
    } else if (!_.contains(result, value)) {
    result.push(value);
    }
    }
    return result;
    };

    _.uniq(array, [isSorted], [iteratee]);
    
    // array -> 需要处理的数组,
    // isSorted -> 是否已经排序
    // iteratee -> 是否自定义排序规则
    
    
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * union
     * 提取并集
     */
    
    // Produce an array that contains the union: each distinct element from all of
    // the passed-in arrays.
    _.union = function() {
        // arguments首先将参数合并为数组,
        // flatten 再将数组扁平化
        // 最后使用_.uniq()对数组去重
        return _.uniq(flatten(arguments, true, true));
    };
    
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * intersection
     * 提取交际
     */
    
    // Produce an array that contains every item shared between all the
    // passed-in arrays.
    _.intersection = function(array) {
        if (array == null) return [];
        var result = [];
        var argsLength = arguments.length;
    
        // 循环第一个arrray,结果肯定在第一个array中存在
        for (var i = 0, length = array.length; i < length; i++) {
            var item = array[i];
            // 如果item在result中存在,则跳出本次循环
            if (_.contains(result, item)) continue;
            // 检查第一个array的item 是否在每一个总都存在,否则退出
            for (var j = 1; j < argsLength; j++) {
                if (!_.contains(arguments[j], item)) break;
            }
            // 如果每个都存在,就保存
            // j === argsLength 意思是为了确保上面的循环跑完了。
            if (j === argsLength) result.push(item);
        }
        return result;
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * intersection
     * 类似于without,但返回的值来自array参数数组,并且不存在于other 数组.
     */
    // Take the difference between one array and a number of other arrays.
    // Only the elements present in just the first array will remain.
    _.difference = function(array) {
        // 现将所有数组扁平化,后面的1值不包含第一个array
        var rest = flatten(arguments, true, true, 1);
        // 然后取出所有真值
        return _.filter(array, function(value){
            // _.contains() 本位比较真值,取反则为假
            return !_.contains(rest, value);
        });
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * zip & unzip
     * 两个差不多,都是讲对应位置的值放在一起,只不过zip是将全部数组放在一个数组中,二unzip是将他们分开成多个
     */
    // Zip together multiple lists into a single array -- elements that share
    // an index go together.
    _.zip = function() {
        return _.unzip(arguments);
    };
    
    // Complement of _.zip. Unzip accepts an array of arrays and groups
    // each array's elements on shared indices
    _.unzip = function(array) {
        // 兼容具有length属性的对象
        var length = array && _.max(array, 'length').length || 0;
        var result = Array(length);
        for (var index = 0; index < length; index++) {
            // _.pluck(array, key),返回所有数组中包含key值的value
            result[index] = _.pluck(array, index);
        }
        return result;
    };
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * object
     * 将键值对数组转换为json,或者将两个数组,对应index的值转为json
     * 有values值 ,则([a, b, c], [1, 2, 3]) -> {a: 1, b: 2, c: 3}
     * 没有则: ([[a, 2], [b, 2], [c, 3]) -> {a: 1, b: 2, c: 3}
     */
    // Converts lists into objects. Pass either a single array of `[key, value]`
    // pairs, or two parallel arrays of the same length -- one of keys, and one of
    // the corresponding values.
    _.object = function(list, values) {
        var result = {};
        for (var i = 0, length = list && list.length; i < length; i++) {
            if (values) {
                // 如果有values则匹配相同的index
                result[list[i]] = values[i];
            } else {
                // 如果只有一个参数,则匹配二维数组的第一个值个第二个值
                result[list[i][0]] = list[i][1];
            }
        }
        return result;
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * indexOf & lastIndexOf
     *  查找索引
     */
    // Return the position of the first occurrence of an item in an array,
    // or -1 if the item is not included in the array.
    // If the array is large and already in sort order, pass `true`
    // for **isSorted** to use binary search.
    _.indexOf = function(array, item, isSorted) {
        var i = 0, length = array && array.length;
    
        if (typeof isSorted == 'number') {
            // 正: 则为本身,负: 则减去它
            i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
        } else if (isSorted && length) {
            // _.sortedIndex(array, item); 将item插入array,能保障排序, i标示插入的索引
            // 其实就是把他插入本来应该在的位置,但是比较的时候却没有,所以就是-1
            i = _.sortedIndex(array, item);
            return array[i] === item ? i : -1;
        }
        // 如果是NaN ,findIndex寻找NaN的位置 -> 数字一定要判断NaN的情况
        if (item !== item) {
            return _.findIndex(slice.call(array, i), _.isNaN);
        }
        for (; i < length; i++) if (array[i] === item) return i;
        return -1;
    };
    
    _.lastIndexOf = function(array, item, from) {
        var idx = array ? array.length : 0;
        // idx不能大于length-1
        if (typeof from == 'number') {
            idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
        }
        // NaN
        if (item !== item) {
            return _.findLastIndex(slice.call(array, 0, idx), _.isNaN);
        }
    
        // --idx = length-1 ,如果有一个相等,则输出,否则返回 -1
        while (--idx >= 0) if (array[idx] === item) return idx;
        return -1;
    };
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * findIndex & findLastIndex
     * 类似于_.indexOf ,只不过indexOf给的是元素,而这个需要表达式
     */
    // Generator function to create the findIndex and findLastIndex functions
    function createIndexFinder(dir) {
        return function(array, predicate, context) {
            predicate = cb(predicate, context);
            var length = array != null && array.length;
            var index = dir > 0 ? 0 : length - 1;
            for (; index >= 0 && index < length; index += dir) {
                // 如果回调函数为true,则输出index
                if (predicate(array[index], index, array)) return index;
            }
            return -1;
        };
    }
    
    // Returns the first index on an array-like that passes a predicate test
    _.findIndex = createIndexFinder(1);
    
    _.findLastIndex = createIndexFinder(-1);
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * sortedIndex
     * 使用二分查找确定value在list中的位置序号
     */
    // Use a comparator function to figure out the smallest index at which
    // an object should be inserted so as to maintain order. Uses binary search.
    _.sortedIndex = function(array, obj, iteratee, context) {
        // 检查iteratee是否存在,是否为对象
        iteratee = cb(iteratee, context, 1);
        var value = iteratee(obj);
        var low = 0, high = array.length;
    
        // 每一次都拿中间值与目标比较,mid+ 1 取后部分,或者high = mid 取前部分,以此类推
        while (low < high) {
            var mid = Math.floor((low + high) / 2);
            if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
        }
        return low;
    };
    
    /*—————————————————————————————————————————————————————————
    

    —————————————————*/

    /**
     * range
     * 一个用来创建整数灵活编号的列表的函数
     */
    
    // Generate an integer Array containing an arithmetic progression. A port of
    // the native Python `range()` function. See
    // [the Python documentation](http://docs.python.org/library/functions.html#range).
    _.range = function(start, stop, step) {
        if (arguments.length <= 1) {
            stop = start || 0;
            start = 0;
        }
        step = step || 1;
        // ceil 向上取整
        // 创建数组及计算数组个数
        var length = Math.max(Math.ceil((stop - start) / step), 0);
        var range = Array(length);
    
        // start 每次都加 step
        for (var idx = 0; idx < length; idx++, start += step) {
            range[idx] = start;
        }
    
        return range;
    };
    

    相关文章

      网友评论

          本文标题:Underscore源码(3)

          本文链接:https://www.haomeiwen.com/subject/sniupttx.html