Underscore源码剖析(二)

本文同步自我得博客:http://www.joeray61.com

近来十几天都在忙毕业论文的事,所以上一次为人人引见完underscore这个框架的构造(或许说是这个框架的设想思绪)以后就一向没动静了,本日我又满血复活了,让我们继承来探究underscore的源码奥妙吧。
没看过上一篇文章的朋侪可以戳这里:underscore源码剖析(一)
本日的内容是underscore内里封装的一些函数,我将逐一引见,我们直接入正题吧

each / _.each / _.forEach

var each = _.each = _.forEach = function(obj, iterator, context) {
    // 不处置惩罚空值
    if(obj == null)
        return;
    if(nativeForEach && obj.forEach === nativeForEach) {
        // 假如宿主环境支撑, 则优先挪用JavaScript 1.6供应的forEach要领
        obj.forEach(iterator, context);
    } else if(obj.length === +obj.length) {
        // 对[数组]中每一个元素实行处置惩罚器要领
        for(var i = 0, l = obj.length; i < l; i++) {
            if( i in obj && iterator.call(context, obj[i], i, obj) === breaker)
                return;
        }
    } else {
        // 对{对象}中每一个元素实行处置惩罚器要领
        for(var key in obj) {
            if(_.has(obj, key)) {
                if(iterator.call(context, obj[key], key, obj) === breaker)
                    return;
            }
        }
    }
};

这个函数的完成头脑实在很简单,假如宿主环境(平常为浏览器或许node.js)支撑原生的forEach要领,就挪用原生的,不然就遍历该数组或许对象,顺次挪用处置惩罚器要领
值得一提的是在推断是不是是数组的时刻,这里的代码为

obj.length === +obj.length

这实际上是一种鸭式辨型的剖断要领,详细可以拜见我在SF上提过的一个题目:点我

_.map / _.collect

_.map = _.collect = function(obj, iterator, context) {
    // 用于寄存返回值的数组
    var results = [];
    if(obj == null)
        return results;
    // 优先挪用宿主环境供应的map要领
    if(nativeMap && obj.map === nativeMap)
        return obj.map(iterator, context);
    // 迭代处置惩罚鸠合中的元素
    each(obj, function(value, index, list) {
        // 将每次迭代处置惩罚的返回值存储到results数组
        results[results.length] = iterator.call(context, value, index, list);
    });
    // 返回处置惩罚效果
    if(obj.length === +obj.length)
        results.length = obj.length;
    return results;
};

map/collect函数与each的区分在于map/collect会存储每次迭代的返回值, 并作为一个新的数组返回

_.reduce / _.foldl / _.inject

_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    // 经由过程参数数目搜检是不是存在初始值
    var initial = arguments.length > 2;
    if(obj == null)
        obj = [];
    // 优先挪用宿主环境供应的reduce要领
    if(nativeReduce && obj.reduce === nativeReduce && false) {
        if(context)
            iterator = _.bind(iterator, context);
        return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    }
    // 迭代处置惩罚鸠合中的元素
    each(obj, function(value, index, list) {
        if(!initial) {
            // 假如没有初始值, 则将第一个元素作为初始值; 假如被处置惩罚的是对象鸠合, 则默许值为第一个属性的值
            memo = value;
            initial = true;
        } else {
            // 纪录处置惩罚效果, 并将效果通报给下一次迭代
            memo = iterator.call(context, memo, value, index, list);
        }
    });
    if(!initial)
        throw new TypeError('Reduce of empty array with no initial value');
    return memo;
};

这个函数的作用是将鸠合中每一个元素放入迭代处置惩罚器, 并将本次迭代的返回值作为memo通报到下一次迭代, 平常用于累计效果或衔接数据

_.reduceRight / _.foldr

_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    var initial = arguments.length > 2;
    if(obj == null)
        obj = [];
    // 优先挪用宿主环境供应的reduceRight要领
    if(nativeReduceRight && obj.reduceRight === nativeReduceRight) {
        if(context)
            iterator = _.bind(iterator, context);
        return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    }
    // 逆转鸠合中的元素递次
    var reversed = _.toArray(obj).reverse();
    if(context && !initial)
        iterator = _.bind(iterator, context);
    // 经由过程reduce要领处置惩罚数据
    return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
};

这个函数与reduce相似,不过它是逆向迭代鸠合中的元素

_.find / _.detect

_.find = _.detect = function(obj, iterator, context) {
    // result寄存第一个可以经由过程考证的元素
    var result;
    // 经由过程any要领遍历数据, 并纪录经由过程考证的元素
    any(obj, function(value, index, list) {
        // 假如处置惩罚器返回的效果被转换为Boolean范例后值为true, 则纪录当前值并返回当前元素
        if(iterator.call(context, value, index, list)) {
            result = value;
            return true;
        }
    });
    return result;
};

这个要领的作用是遍历鸠合中的元素, 返回可以经由过程处置惩罚器考证的第一个元素

_.filter / _.select

_.filter = _.select = function(obj, iterator, context) {
    // 用于存储经由过程考证的元素数组
    var results = [];
    if(obj == null)
        return results;
    // 优先挪用宿主环境供应的filter要领
    if(nativeFilter && obj.filter === nativeFilter)
        return obj.filter(iterator, context);
    // 迭代鸠合中的元素, 并将经由过程处置惩罚器考证的元素放到数组中并返回
    each(obj, function(value, index, list) {
        if(iterator.call(context, value, index, list))
            results[results.length] = value;
    });
    return results;
};

这个要领与find作用相似, 但它会纪录下鸠合中所有经由过程考证的元素

_.reject

_.reject = function(obj, iterator, context) {
    var results = [];
    if(obj == null)
        return results;
    each(obj, function(value, index, list) {
        if(!iterator.call(context, value, index, list))
            results[results.length] = value;
    });
    return results;
};

这个要领的代码内里我没有加解释,由于全部代码与filter/select要领险些一样,不同点在于向results数组里增加元素的时刻推断前提是相反的,也就是说这个要领的作用是返回没有经由过程处置惩罚器考证的元素列表

_.every / _.all

_.every = _.all = function(obj, iterator, context) {
    var result = true;
    if(obj == null)
        return result;
    // 优先挪用宿主环境供应的every要领
    if(nativeEvery && obj.every === nativeEvery)
        return obj.every(iterator, context);
    // 迭代鸠合中的元素
    each(obj, function(value, index, list) {
        // 这里我不太明白,为何药写成 result = (result && iterator.call(context, value, index, list)) 而不是 result = iterator.call(context, value, index, list)
        if(!( result = result && iterator.call(context, value, index, list)))
            return breaker;
    });
    return !!result;
};

这个要领的作用是假如鸠合中所有元素均能经由过程处置惩罚器考证, 则返回true

any / _.some / _.any

var any = _.some = _.any = function(obj, iterator, context) {
    // 假如没有指定处置惩罚器参数, 则运用默许的处置惩罚器函数,该函数会返回参数自身
    iterator || ( iterator = _.identity);
    var result = false;
    if(obj == null)
        return result;
    // 优先挪用宿主环境供应的some要领
    if(nativeSome && obj.some === nativeSome)
        return obj.some(iterator, context);
    // 迭代鸠合中的元素
    each(obj, function(value, index, list) {
        if(result || ( result = iterator.call(context, value, index, list)))
            return breaker;
    });
    return !!result;
};

该函数的作用是搜检鸠合中是不是有任何一个元素在被转换成Boolean范例时是不是为true

_.include / _.contains

_.include = _.contains = function(obj, target) {
    var found = false;
    if(obj == null)
        return found;
    // 优先挪用宿主环境供应的Array.prototype.indexOf要领
    if(nativeIndexOf && obj.indexOf === nativeIndexOf)
        return obj.indexOf(target) != -1;
    // 经由过程any要领迭代鸠合中的元素, 考证元素的值和范例与目的是不是完整婚配
    found = any(obj, function(value) {
        return value === target;
    });
    return found;
};

这个函数用于搜检鸠合中是不是有值与目的参数完整婚配,包含数据范例

小结

本日先引见以上10个函数的完成细节,以后还会继承带来其他函数的引见,迎接人人提出指正和发起,thx for reading, hope u enjoy

    原文作者:JoeRay61
    原文地址: https://segmentfault.com/a/1190000000531871
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞