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));
};
});