underscore源码剖析之基本要领

underscore源码理会之基本要领

本文是underscore源码理会系列的第二篇,重要引见underscore中一些基本要领的完成。

mixin

在上篇文章underscore团体架构理会中,我们讲过_上面的要领有两种挂载体式格局,一个是挂载到_组织函数上以_.map(arr)的情势直接挪用(在后文上统称组织函数挪用),另一种则是挂到_.prototype上以_(arr).map()的情势被实例挪用(在后文上统称原型挪用)

翻一遍underscore源码你会发明underscore中的要领都是直接挂到_组织函数上完成的,然则会经由过程mixin要领来将_上面的要领扩展到_.prototype上面,如许这些要领既可以直接挪用,又可以经由过程实例来挪用。

_.mixin = function(obj) {
    // 遍历obj上一切的要领
    _.each(_.functions(obj), function(name) {
        // 保留要领的援用
        var func = _[name] = obj[name];
        _.prototype[name] = function() {
            // 将一开始传入的值放到数组中
            var args = [this._wrapped];
            // 将要领的参数一同push到数组中(这里处置惩罚的很好,保证了func要领参数的递次)
            push.apply(args, arguments);
            // 这里先用apply要领实行了func,并将效果传给了result
            return result(this, func.apply(_, args));
        };
    });
};

_.mixin(_);

从这段代码中我们可以看出,mixin要领将_上的一切要领经由过程遍历的情势挂载到了_.prototype上面。

仔细视察一下,组织函数挪用和原型挪用的区分在那里?
没错,区分就在于挪用体式格局和传参,组织函数挪用时平常会把要处置惩罚的值当作第一个参数传入,而原型挪用的时刻会把要处置惩罚的值传入_组织函数来建立一个实例。

var arr = [1, 2, 3]
var func = function(item) {
    console.log(item);
}
// 组织函数挪用时arr被传入第一个参数
_.each(arr, func)
// 原型挪用的时刻,arr被当作参数传给_要领来建立一个实例
_(arr).each(func)
// 链式挪用,和上面相似
_.chain(arr).each(func)

从上一节中我们晓得,在建立一个_的实例时,会用this._wrapped将传入的值保留起来,所以在mixin内里这一句:var args = [this._wrapped];是将我们传给_的值放到args数组第一项中,以后再将arguments也放入args数组中,借助apply要领实行当前遍历的要领(在这个例子中是each),这个时刻传给each要领的是arr和func,恰好和本来直接_.each挪用each传入参数的递次是一样的(underscore中的要领第一项基本上都是要处置惩罚的数据)。

链式挪用

那末上面末了return result(this, func.apply(_, args)),result又是做什么的呢?

起首来看result源码:

var result = function(instance, obj) {
    // 起首推断是不是运用链式挪用,假如是,那就继承将方才实行后返回的效果链式挪用一下,假如不是,则直接返回实行后的效果
    return instance._chain ? _(obj).chain() : obj;
};
_.chain = function(obj) {
    // 建立一个实例
    var instance = _(obj);
    // 给这个实例加个_chain属性来表明这是链式挪用
    instance._chain = true;
    return instance;
};

我们晓得underscore中也是有和jQuery相似的链式挪用,来看一下链式挪用的例子:

var arr = [1, 2, 3]
var newArr = _.chain(a).map(function(item) {
    return item + 1
}).filter(function(item) {
    return item > 2
}).value()

链式挪用的关键在于每次实行要领后都须要返回一个实例,以确保可以继承挪用其他要领。
chain要领会用传入的obj建立一个_的实例,这个实例可以挪用原型上的要领。从上面mixin的完成来看,每次挪用原型要领后会将实行后的效果传给result要领,在result内部会推断你是不是运用了链式挪用(chain),假如是链式的,那末就会将返回效果链式化(传入chain中建立新的实例)。
链式挪用肯定要在末端实行value要领,不然末了返回的是一个对象(末了一次建立的_实例)

数组函数

underscore组织要领上面并没有直接对push、pop、shift等数组要领举行完成,然则链式挪用的时刻每每须要用到这些要领,所以在原型上对这些要领做了一些封装,完成要领和mixin相似,这里不再多做诠释。

_.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    var method = ArrayProto[name];
    _.prototype[name] = function() {
    var obj = this._wrapped;
    method.apply(obj, arguments);
    // 这句是彷佛是为了处理ie上的bug?
    if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
        return result(this, obj);
    };
});

_.each(['concat', 'join', 'slice'], function(name) {
    var method = ArrayProto[name];
    _.prototype[name] = function() {
        return result(this, method.apply(this._wrapped, arguments));
    };
});
    原文作者:尹光耀
    原文地址: https://segmentfault.com/a/1190000013828016
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞