资讯专栏INFORMATION COLUMN

underscore.js 源码学习 array(未完待续)

tomato / 1440人阅读

摘要:如果为空的情况下,也为空返回,不为空返回为空,返回数组第一个元素返回包含数组前个元素的数组返回数组中除了最后一个元素外的其他全部元素。

    // Array Functions
    // ---------------
    // 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为空的情况下,n也为空返回undefined,n不为空返回[]
        if (array == null || array.length < 1) return n == null ? void 0 : [];
        //n为空,返回数组第一个元素
        if (n == null || guard) return array[0];
        //返回包含数组前n个元素的数组
        return _.initial(array, array.length - n);
    };
    

    // 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.
    // 返回数组中除了最后一个元素外的其他全部元素。 在arguments对象上特别有用。
    // 传递 n参数将从结果中排除从最后一个开始的n个元素(注:排除数组后面的 n 个元素)。
    _.initial = function(array, n, guard) {
        return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
    };
        // Get the last element of an array. Passing **n** will return the last N
        // values in the array.
        // 返回数组的后n个元素
    _.last = function(array, n, guard) {
        if (array == null || array.length < 1) return n == null ? void 0 : [];
        if (n == null || guard) return array[array.length - 1];
        return _.rest(array, Math.max(0, array.length - n));
    };
        // 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.
        // 返回从n个索引开始的元素
    _.rest = _.tail = _.drop = function(array, n, guard) {
        return slice.call(array, n == null || guard ? 1 : n);
    };
        // Trim out all falsy values from an array.
        // 返回数组中的真值
       
    
         _.compact = function(array) {
                return _.filter(array, Boolean);
            };
        // Internal implementation of a recursive `flatten` function.
        // 将嵌套多层数组转换为一位数组
       
    
         var flatten = function(input, shallow, strict, output) {
                output = output || [];
                var idx = output.length;
                for (var i = 0, length = getLength(input); i < length; i++) {
                    var value = input[i];
                    // 元素类型为数组或者参数
                    if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
                        // Flatten current level of array or arguments object.
                        // 传入shallow的情况下,只展开一层就不再深入
                        if (shallow) {
                            var j = 0,
                                len = value.length;
                            while (j < len) output[idx++] = value[j++];
                        } else {// 否则,迭代展开。
                            flatten(value, shallow, strict, output);
                            idx = output.length;
                        }
                    } 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);
    };
        // Return a version of the array that does not contain the specified value(s).
        // 返回一个删除所有values值后的 array副本。(注:使用===表达式做相等测试。)
    _.without = restArguments(function(array, otherArrays) {
        return _.difference(array, otherArrays);
    });
        // Produce a duplicate-free version of the array. If the array has already
        // been sorted, you have the option of using a faster algorithm.
        // The faster algorithm will not work with an iteratee if the iteratee
        // is not a one-to-one function, so providing an iteratee will disable
        // the faster algorithm.
        // Aliased as `unique`.
        // 返回 array去重后的副本, 使用 === 做相等测试. 
        // 如果您确定 array 已经排序, 那么给 isSorted 参数传递 true值, 此函数将运行的更快的算法. 
        // 如果要处理对象元素, 传递 iteratee函数来获取要对比的属性。
    _.uniq = _.unique = function(array, isSorted, iteratee, context) {
        // 类似jq,做参数兼容方案
        if (!_.isBoolean(isSorted)) {
            context = iteratee;
            iteratee = isSorted;
            isSorted = false;
        }
        if (iteratee != null) iteratee = cb(iteratee, context);
        var result = [];
        var seen = [];
        for (var i = 0, length = getLength(array); i < length; i++) {
            var value = array[i],
                computed = iteratee ? iteratee(value, i, array) : value;
            // 如果数组有序,且不存在迭代器
            if (isSorted && !iteratee) {
                // 如果计算结果不等于seen中,或者i为第一个元素,将元素存入result中
                if (!i || seen !== computed) result.push(value);
                // 将seen替换为最新结果
                seen = computed;
            } else if (iteratee) {//如果存在迭代器
                if (!_.contains(seen, computed)) {//如果seen中不包含计算结果
                    seen.push(computed);//计算结果存入seen中
                    result.push(value);//元素存入result中
                }
            } else if (!_.contains(result, value)) {//如果不存在迭代器
                result.push(value);
            }
        }
        return result;
    };
        // Produce an array that contains the union: each distinct element from all of
        // the passed-in arrays.
       
    
         _.union = restArguments(function(arrays) {
                // 将数组展开后去重
                return _.uniq(flatten(arrays, true, true));
            });
        // Produce an array that contains every item shared between all the
        // passed-in arrays.
        // 返回传入 arrays(数组)交集。结果中的每个值是存在于传入的每个arrays(数组)里。
    _.intersection = function(array) {
        var result = [];
        var argsLength = arguments.length;
        for (var i = 0, length = getLength(array); i < length; i++) {
            var item = array[i];
            // 元素已存在于result中,则继续下一个循环
            if (_.contains(result, item)) continue;
            var j;
            for (j = 1; j < argsLength; j++) {
                if (!_.contains(arguments[j], item)) break;
            }
            //如果所有参数都包含item,则item为交集元素
            if (j === argsLength) result.push(item);
        }
        return result;
    };
        // Take the difference between one array and a number of other arrays.
        // Only the elements present in just the first array will remain.
        // array中与rest不同的值
       
    
         _.difference = restArguments(function(array, rest) {
                rest = flatten(rest, true, true);
                return _.filter(array, function(value) {
                    return !_.contains(rest, value);
                });
            });
        // Complement of _.zip. Unzip accepts an array of arrays and groups
        // each array"s elements on shared indices.
        // 将每个 arrays 中相应位置的值合并在一起。 
        // 当您有通过匹配数组索引进行协调的独立数据源时,这非常有用。 
        // 结合 apply 一起使用传入一个二维数组。
        // 如果你用来处理矩阵嵌套数组时,则可以使用它来转换矩阵。
    _.unzip = function(array) {
        var length = array && _.max(array, getLength).length || 0;
        var result = Array(length);
        for (var index = 0; index < length; index++) {
            result[index] = _.pluck(array, index);
        }
        return result;
    };
        // Zip together multiple lists into a single array -- elements that share
        // an index go together.
       
        // 将多个数组,合成一个。
     _.zip = restArguments(_.unzip);
        // 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. Passing by pairs is the reverse of _.pairs.
        // 将数组转换为对象。传递任何一个多带带[key, value]对的列表,或者一个键的列表和一个值得列表。成对(Pairs)传递 则是 pairs 的反函数。 
        // 如果存在重复键,最后一个值将被返回。
    _.object = function(list, values) {
        var result = {};
        for (var i = 0, length = getLength(list); i < length; i++) {
            if (values) {
                result[list[i]] = values[i];
            } else {
                result[list[i][0]] = list[i][1];
            }
        }
        return result;
    };
        // Generator function to create the findIndex and findLastIndex functions.
    var createPredicateIndexFinder = function(dir) {
        return function(array, predicate, context) {
            predicate = cb(predicate, context);
            var length = getLength(array);
            //正向起始位置为0,反向起始位置为数组末尾length-1
            var index = dir > 0 ? 0 : length - 1;
            for (; index >= 0 && index < length; index += dir) {
                if (predicate(array[index], index, array)) return index;
            }
            return -1;
        };
    };
        // Returns the first index on an array-like that passes a predicate test.
    _.findIndex = createPredicateIndexFinder(1);
    _.findLastIndex = createPredicateIndexFinder(-1);
        // 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.
        // 假设array是有序,且是升序
        // 返回iteratee(obj)值在array中的iteratee(array(index))的位置index
    _.sortedIndex = function(array, obj, iteratee, context) {
        iteratee = cb(iteratee, context, 1);
        var value = iteratee(obj);
        var low = 0,
            high = getLength(array);
        while (low < high) {
            var mid = Math.floor((low + high) / 2);
            if (iteratee(array[mid]) < value) low = mid + 1;
            else high = mid;
        }
        return low;
    };
        // Generator function to create the indexOf and lastIndexOf functions.
    var createIndexFinder = function(dir, predicateFind, sortedIndex) {
        return function(array, item, idx) {
            var i = 0,
                length = getLength(array);
            //存在初始位置
            if (typeof idx == "number") {
                //正向,改变起始位置
                if (dir > 0) {
                    //起始位置 = idx为正?idx:取(length+idx)与0中的最大值
                    i = idx >= 0 ? idx : Math.max(idx + length, i);
                } else {//反向,改变数组长度
                    //lastIndexOf函数功能:
                    //lastIndexOf(searchValue,fromIndex)
                    //若在0-fromIndex之间存在searchValue,则返回最后一个出现的位置
                    //fromIndex为正值,范围则是0-abs(fromIndex)
                    //fromIndex为负值,范围则是0-(length-abs(fromIndex))??此处为什么有+1
                    //看了原生lastIndexOf中就是如此设置的。
                    //数组长度=idx为正?取(idx+1,length):idx + length + 1
                    length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
                }
            //idx数值以外的值(isSorted=true),默认array为有序数组,使用sortedIndex查找item位置
            } else if (sortedIndex && idx && length) {
                idx = sortedIndex(array, item);
                return array[idx] === item ? idx : -1;
            }
            //--------------自我理解可简写----------
            //查找值为NaN
            if (item !== item) {
                idx = predicateFind(slice.call(array, i, length), _.isNaN);
                return idx >= 0 ? idx + i : -1;
            }
            for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
                if (array[idx] === item) return idx;
            }
            return -1;
            //--------------自我理解可简写为如下----------
            var iteratee = null;
            if(item!==item) iteratee = _.isNaN
            idx = predicateFind(slice.call(array, i, length), iteratee);
            return idx >= 0 ? idx + i : -1;
            
        };
    };
        // 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.
        // 如果array数值大且是升序,可以设置_.indexOf(array,item,isSorted=true),使用二进制搜索。
    _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
    _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
        // 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 (stop == null) {
            stop = start || 0;
            start = 0;
        }
        if (!step) {
            step = stop < start ? -1 : 1;
        }
        var length = Math.max(Math.ceil((stop - start) / step), 0);
        var range = Array(length);
        for (var idx = 0; idx < length; idx++, start += step) {
            range[idx] = start;
        }
        return range;
    };
        // Chunk a single array into multiple arrays, each containing `count` or fewer
        // items.
        // 将 array 分成多个数组,每个数组包含length 或更少的项。
    _.chunk = function(array, count) {
        if (count == null || count < 1) return [];
        var result = [];
        var i = 0,
            length = array.length;
        while (i < length) {
            result.push(slice.call(array, i, i += count));
        }
        return result;
    };

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/103762.html

相关文章

  • 打造属于自己的underscore系列 ( 一 )

    摘要:目前通行的模块规范主要集中在和,因此为了让定义的库能够适用于各种规范。在框架的定义时需检测使用环境并兼容各种规范。服务端规范,检测是否存在,满足时通过将暴露出来,不满足则通过对象暴露出来。前者回调函数处理的是值和下标,后者处理的是值和属性。 本文为博主原创文章,转载请注明出处 https://www.cnblogs.com/kidfl... underscore作为开发中比较常用的一个...

    nifhlheimr 评论0 收藏0
  • 【半月刊 4】前端高频面试题及答案汇总

    摘要:引言半月刊第四期来啦,这段时间新增了道高频面试题,今天就把最近半月汇总的面试题和部分答案发给大家,帮助大家查漏补缺,欢迎加群互相学习。更多更全的面试题和答案汇总在下面的项目中,点击查看。引言 半月刊第四期来啦,这段时间 Daily-Interview-Question 新增了 14 道高频面试题,今天就把最近半月汇总的面试题和部分答案发给大家,帮助大家查漏补缺,欢迎 加群 互相学习。 更多更...

    hankkin 评论0 收藏0
  • Vue学习笔记(未完待续

    摘要:但是正则表达式需要特殊处理当匹配到第一个非封闭的符号时,要校验它之前的第一个非空字符。采用正则表达式来匹配这一规则匹配任意 代码细节 缓存代理函数 export function cached (fn: F): F { const cache = Object.create(null) return (function cachedFn (str: string) { ...

    LuDongWei 评论0 收藏0
  • underscore 源码解读】如何优雅地写一个『在数组中寻找指定元素』的方法

    摘要:今天要讲的是,如何在数组中寻找元素,对应中的,,,以及方法。如果往一个有序数组中插入元素,使得数组继续保持有序,那么这个插入位置是这就是这个方法的作用,有序,很显然用二分查找即可。 Why underscore (觉得这部分眼熟的可以直接跳到下一段了...) 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中。 阅读一...

    0x584a 评论0 收藏0
  • underscore源码学习(一)

    摘要:所以,刚开始,我从源码比较短的包含注释只有行开始学习起。一般,在客户端浏览器环境中,即为,暴露在全局中。学习以后判断直接使用看起来也优雅一点滑稽脸。在的函数视线中,的作用执行一个传入函数次,并返回由每次执行结果组成的数组。 前言 最近在社区浏览文章的时候,看到了一位大四学长在寻求前端工作中的面经,看完不得不佩服,掌握知识点真是全面,无论是前端后台还是其他,都有涉猎。 在他写的文章中,有...

    gclove 评论0 收藏0

发表评论

0条评论

tomato

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<