天天看点

V-1.8.2 underscore源码解析(五)

V-1.8.2 underscore源码解析(五)

_.countBy = group(function(result, value, key) {
        if(_.has(result, key)) result[key]++;
        else result[key] = ;
    });
           
//  _.countBy([1, 2, 3, 4, 5], function(num) {
//   return num % 2 == 0 ? 'even': 'odd';
// });
// => {odd: 3, even: 2}

// Safely create a real, live array from anything iterable.
// 把list(任何可以迭代的对象)转换成一个数组,在转换 arguments 对象时非常有用。
           
_.toArray = function(obj) {
        // 将boolean、为falsy值得字符串、null 、undefined
        // 返回一个空数组
        // 伪数组 -> 数组
        // 对象 -> 提取 value 值组成数组
        if(!obj) return [];
        if(_.isArray(obj)) return slice.call(obj);
        // 如果是类数组,则重新构造新的数组
        if(isArrayLike(obj)) return _.map(obj, _.identity);
        // 如果是对象,则返回 values 集合
        return _.value(obj);
    }
           
// _.toArray({name:"tom",age:23})
// (2) ["tom", 23]
// _.toArray('121e1wwef')
// (9) ["1", "2", "1", "e", "1", "w", "w", "e", "f"]
// _.toArray(true)
// []
// _.toArray(' ')
// [" "]

// Return the number of elements in an object.
// 返回obj中元素的个数
           
_.size = function(obj) {
        if(obj == null) return ;
        // 若是类数组,则返回数组的长度,若是对象,则返回key构成的数组的长度
        return isArrayLike(obj) ? obj.length : _.keys(obj).length;
    };
           
// Split a collection into two arrays: one whose elements all satisfy the given
// predicate, and one whose elements all do not satisfy the predicate.
// 将一个集合划分成2个数组,一个全部满足predicate函数真值检测,另一个全不满足
           
_.partition = function(obj, predicate, context) {
        predicate = cb(predicate, context);
        var pass = [],
            fail = [];
        _.each(obj, function(value, key, obj) {
            (predicate(value, key, obj) ? pass : fail).push(value);
        });
        // 返回一个二维数组,元素为[pass]和[fail]数组
        return [pass, fail];
    };
           
// Array Functions   数组的扩展方法
// ---------------
// 所有的数组函数也可以用于 arguments (参数)对象。 但是,Underscore 函数不能用于稀疏("sparse" )数组。
// 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`.
// 获取数组中的第一个元素,通过设定参数n值,返回数组前 n 个元素(组成的数组)
           
_.first = _.head = _.take = function(array, n, guard) {
        // array为null或者undefined ,则返回undefined
        // array只能为数组或者在arguments对象
        if(array == null) return void ;
        // 如果n 和 guard都存在且不为null/undefined,或都不存在,则返回数组的第一个值
        if(n == null || guard) return array[];
        // 只存在n,返回数组前n个元素构成的数组
        return _.initial(array, array.length - n);
    };
           
// _.first([2,3,5,6,7],2)
// (2) [2, 3]
// _.first([2,3,5,6,7],2,4)
// 2
// _.first([2,3,5,6,7])
// 2

// _.first({name:'tom',age:23,sex:'men'},0)
// []
// _.first({name:'tom',age:23,sex:'men'})
// undefined
/*      
            <div>2</div>
            <div>3</div>
            <div>4</div>
        var div = document.getElementsByTagName('div');
        var res1  = _.first(div,2);
            [div, div]
        var res  = _.first(div,1)[0].innerHTML;
        console.log(res); //2
*/

// 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.
// 与_.first相反,
// 传入一个数组
// 返回剔除最后一个元素之后的数组副本
// 如果传入参数 n,则剔除最后 n 个元素
           
_.initial = function(array, n, guard) {
        return slice.call(array, , Math.max(, array.length - (n == null || guard ?  : n)));
    };
           
//  _.initial([2,4,6,8],2)
// (2) [2, 4]
// _.initial([2,4,6,8],1)
// (3) [2, 4, 6]

// Get the last element of an array. Passing **n** will return the last N
// values in the array.
// last和first方法相反,last是从后面开始计数,
// 返回array(数组)中最后一个元素。传递 n参数将返回
// 数组中从最后一个元素开始的n个元素(返回数组里的后面
// 的n个元素)。
           
_.last = function(array, n, guard) {
        if(array == null) return void ;
        if(n == null || guard) return array[array.length - ];
        return _.rest(array, Math.max(, array.length - n));
    };
           
//  _.last([3,5,7,8],2)
// (2) [7, 8]

// 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 ?  : n);
    };
           
// rest_.rest(array, [index]) Alias: tail, drop 
// 返回数组中除了第一个元素外的其他全部元素。
// 传递 index 参数将返回从index开始的剩余所有元素 。

// Trim out all falsy values from an array.
// 返回一个去除了false值的array副本,在JavaScript中属于falsy值得
// 有 false ,0,'',null,undefined,NaN
           
_.compact = function(array) {
        return _.filter(array, _.identity);
    }
           
// 递归的一个内部实现
// Internal implementation of a recursive `flatten`  function 
           
var flatten = function(input, shallow, strict, startIndex) {
        var output = [],
            idx = ;
        for(var i = startIndex || , length = input && input.length; i < length; i++) {
            var value = input[i];
            // 判断input中参数是否为数组 
            if(isArrayLike() && (_.Array(value) || _.isArguments(value))) {
                // 根据shallow的值来决定是否继续递归
                if(!shallow) value = flatten(value, shallow, strict);
                // 将value中的值添加到output新数组中
                var j = ,
                    len = value.length;
                while(j < len) {
                    output[idx++] = value[j++];
                }
                // 若不是数组,则直接将value放入新数组
            } else if(!strict) {
                output[idx++] = value;
            }
        }
        //返回的是一个新数组
        return output;
    }
           
// Flatten out an array, either recursively (by default), or just one level.
//      将一个嵌套多层的数组 array(数组) (嵌套可以是任何层数)转换为只有一层的数组。 如果你传递 shallow参数,数组将只减少一维的嵌套。
           
_.flatten = function(array, shallow) {
        return flatten(array, shallow, false);
    };
           
// Return a version of the array that does not contain the specified value(s).
//返回一个删除所有values值后的 array副本。(愚人码头注:使用===表达式做相等测试。),就相当于一个过滤函数,将array中包含values的值全部去除掉,返回一个剩余值得新数组
           
_.without = function(array, * values) {
        return _.difference(array, slice.call(arguments, ));
    };
           
//  返回 array去重后的副本, 使用 === 做相等测试. 如果您确定 array 已经排序, 那么给 isSorted 参数传递 true值, 此函数将运行的更快的算法. 如果要处理对象元素, 传递 iteratee函数来获取要对比的属性.
// 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 [];
        // 判断是否已进行排序,若已排序,节省运算步骤,能提高速度
        if(!_.isBoolean(isSorted)) {
            context = iteratee;
            iteratee = isSorted;
            isSorted = false;
        }
        if(iteratee != null) iteratee = cb(iteratee, context);
        var result = [];
        var seen = [];
        for(var i = , length = array.length; i < length; i++) {
            var value = array[i],
                computed = iteratee ? iteratee(value, i, array) : value;
            if(isSorted) {
                if(!i || seen !== computed) result.push(value);
                seen = computed;
            } else if(iteratee) {
                // 判断是否存在,不存在则push
                if(!_.contains(seen, computed)) {
                    seen.push(computed);
                    result.push(value);
                }
            } else if(!_.contains(result, value)) {
                result.push(value);
            }
        }
        return result;
    };
           
//  _.union(*arrays) 
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
//  返回传入的 arrays(数组)并集:按顺序返回,返回数组的元素是唯一的,可以传入一个或多个 arrays (数组),由于其中调用了flatten方法,而flatten方法可以将嵌套数组转为一维数组,由于第二个参数是true,故flatten是将嵌套数组减一维进行运算,故可以传入多个数组,然后在调用uniq方法进行去重【' === '】
           
_.union = function() {
        return _.uniq(flatten(arguments, true, true));
    };

    // 返回一个交叉数组,即每个数组中都含有的项,即多个数组的交集
    // Produce an array that contains every item shared between all the
    // passed-in arrays.
    _.intersection = function(array) {
        // 若array为null或者undefined,则返回一个空数组
        if(array == null) return [];
        var result = [];
        var argsLength = arguments.length;
        // 依次将array中的每一项中的item和arguments的下一项比较,当比较到最后一项时,若这些项中都含有item,则将其push如result数组

        for(var i = , length = array.length; i < length; i++) {
            var item = array[i];
            if(_.contains(result, item)) continue;
            for(var j = ; j < argsLength; j++) {
                if(!_.contains(arguments[j], item)) break;
            }
            if(j === argsLength) result.push(item);
        }
        return result;
    };
           
//  将第一个数组和另一个数组比较,类似于without,返回的是第一个数组中的值组成的副本,若第一个数组和另一个数组含有相同的值,则返回的新数组需要去除这些相同的值
// 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) {
        var rest = flatten(arguments, true, true, );
        return _.filter(array, function(value) {
            return !_.contains(rest, value);
        });
    };
           
// Zip together multiple lists into a single array -- elements that share
// an index go together.
//  将 每个arrays中相应位置的值合并在一起。在合并分开保存的数据时很有用. 如果你用来处理矩阵嵌套数组时, _.zip.apply 可以做类似的效果。
           
_.zip = function() {
        return _.unzip(arguments);
    };
           
//  _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
//=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

// Complement of _.zip. Unzip accepts an array of arrays and groups
// each array's elements on shared indices
//  与zip功能相反的函数,给定若干arrays,返回一串联的新数组,其第一元素个包含所有的输入数组的第一元素,其第二包含了所有的第二元素,依此类推。通过apply用于传递数组的数组。
           
_.unzip = function(array) {
        var length = array && _.max(array, 'length').length || ;
        // 声明一个指定长度的数组
        var result = Array(length);
        //      将多个数组中的相同索引的值放入一个数组
        for(var index = ; index < length; index++) {
            result[index] = _.pluck(array, index);
        }
        return result;
    };
           
// 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.
           

// 将数组转换为对象。传递任何一个单独[key, value]对的列表,或者一个键的列表和一个值得列表。 如果存在重复键,最后一个值将被返回。

_.object = function(list, values) {
        var result = {};
        for(var i = , length = list && list.length; i < length; i++) {
            if(values) {
                result[list[i]] = values[i];
            } else {
                result[list[i][]] = list[i][];
            }
        }
        return result;
    };
           

继续阅读