您的位置:首页 > 其它

underscore源码解析(集合)

2015-11-16 17:25 211 查看
underscore就是一些函数的集合,大概分为6部分,分别是基础函数,集合,数组,函数,对象,实用功能.

在实现每一个功能的时候,基本上先自己实现,再对比。

(function(){

}.call(this));
基本框架长这样,就一个函数的自调用,用window作为调用对象,防止污染全局。

//把window对象先存起来备用吧。
varroot=this;
//弄个window的属性_;
varpreviousUnderscore=root._;
//存一些原型
varArrayProto=Array.prototype,ObjProto=Object.prototype,FuncProto=Function.prototype;
//存一些原型的方法
var
push=ArrayProto.push,
slice=ArrayProto.slice,
toString=ObjProto.toString,
hasOwnProperty=ObjProto.hasOwnProperty;

var
nativeIsArray=Array.isArray,
nativeKeys=Object.keys,
nativeBind=FuncProto.bind,
nativeCreate=Object.create;
//弄个备用的构造函数
varCtor=function(){};

//构造函数_,obj是_实例的话,直接返回obj.若是直接调用构造函数而不是通过new操作符的话,会调用第二个if.执行new_(obj).
//另外,这样的话obj就不是实例了,所以弄个实例属性_wrapped把obj存起来备用。
var_=function(obj){
if(objinstanceof_)returnobj;
if(!(thisinstanceof_))returnnew_(obj);
this._wrapped=obj;
};
//这个是什么nodejs接口的,不懂。过了,嘿嘿

if(typeofexports!=='undefined'){
if(typeofmodule!=='undefined'&&module.exports){
exports=module.exports=_;
}
exports._=_;
}else{
root._=_;
}

//这个是关于函数优化的,参数函数,调用EC,参数数量。
//只传了一个参数的话,context==null.这里应该是可以用context===void0或者context==null,一个意思。直接返回传入的函数
//没传第三个参数的话,默认就是传三个参数给调用的函数,一般是用在forEach,filter这些数组方法,function(element,index,array);
//第三个参数是1或2的话,感觉没什么特别的,直接调用吧.是4的话就是reduce函数之类的。
varoptimizeCb=function(func,context,argCount){
if(context===void0)returnfunc;
switch(argCount==null?3:argCount){
case1:returnfunction(value){
returnfunc.call(context,value);
};
case2:returnfunction(value,other){
returnfunc.call(context,value,other);
};
case3:returnfunction(value,index,collection){
returnfunc.call(context,value,index,collection);
};
case4:returnfunction(accumulator,value,index,collection){
returnfunc.call(context,accumulator,value,index,collection);
};
}
returnfunction(){
returnfunc.apply(context,arguments);
};
};

//没传参数的话,直接返回一个函数,设置a,调用这个函数a,返回传给a的参数
//value是函数的话,直接调用上面的函数优化公式,
//对象的话,返回是否对象匹配的函数。
//返回一个property函数,这个函数调用传一个对象,value是键,返回值

varcb=function(value,context,argCount){
if(value==null)return_.identity;
if(_.isFunction(value))returnoptimizeCb(value,context,argCount);
if(_.isObject(value))return_.matcher(value);
return_.property(value);
};

_.identity=function(value){
returnvalue;
};
_.property=function(key){
returnfunction(obj){
returnobj==null?void0:obj[key];
};
};
//源码中没有用到。返回一个迭代函数吧。
_.iteratee=function(value,context){
returncb(value,context,Infinity);
};
//创建一个对象合并器.keyfunc是一个对象键数组函数,返回对象所有键。
//undefinedOnly么是定义是不是只有往目标对象上添加属性而不管属性是否存在。一般为
//true。也就是当对象不存在这个属性的时候才添加。
//当返回的函数只有一个参数时或者直接调用,直接返回那个参数。
//否则把对象的参数一个个遍历出来,添加到新对象,再返回新对象

//放个参考的
//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

varcreateAssigner=function(keysFunc,undefinedOnly){
returnfunction(obj){
varlength=arguments.length;
if(length<2||obj==null)returnobj;
for(varindex=1;index<length;index++){
varsource=arguments[index],
keys=keysFunc(source),
l=keys.length;
for(vari=0;i<l;i++){
varkey=keys[i];
if(!undefinedOnly||obj[key]===void0)obj[key]=source[key];
}
}
returnobj;
};
};

//创建一个对象,原型是参数prototype
//参数不是对象的话,直接返回
//有原生的Object.create方法的话直接用
//利用Ctor构造函数创建对象原型。
varbaseCreate=function(prototype){
if(!_.isObject(prototype))return{};
if(nativeCreate)returnnativeCreate(prototype);
Ctor.prototype=prototype;
varresult=newCtor;
Ctor.prototype=null;
returnresult;
};

//数组索引的最大值
varMAX_ARRAY_INDEX=Math.pow(2,53)-1;

//是不是类数组,包括原生数组和nodelist类型
varisArrayLike=function(collection){
varlength=collection&&collection.length;
returntypeoflength=='number'&&length>=0&&length<=MAX_ARRAY_INDEX;
};

//前面一些基础函数写完了。写正式的了。首先集合方法。

//对数组和对象的键集合进行迭代遍历.每个key调用函数,返回原来的obj

_.each=_.forEach=function(obj,iteratee,context){
//iteratee默认3个参数
iteratee=optimizeCb(iteratee,context);
vari,length;
//数组直接遍历,对象遍历键集合
if(isArrayLike(obj)){
for(i=0,length=obj.length;i<length;i++){
iteratee(obj[i],i,obj);
}
}else{
varkeys=_.keys(obj);
for(i=0,length=keys.length;i<length;i++){
iteratee(obj[keys[i]],keys[i],obj);
}
}
returnobj;
};

//每个key调用函数,返回调用后集合数组

_.map=_.collect=function(obj,iteratee,context){
iteratee=cb(iteratee,context);
//数组和对象的不同处理。
varkeys=!isArrayLike(obj)&&_.keys(obj),
length=(keys||obj).length,
results=Array(length);
for(varindex=0;index<length;index++){
varcurrentKey=keys?keys[index]:index;
results[index]=iteratee(obj[currentKey],currentKey,obj);
}
returnresults;
};
//参数一大堆先不看了。黑
functioncreateReduce(dir){

functioniterator(obj,iteratee,memo,keys,index,length){
for(;index>=0&&index<length;index+=dir){
varcurrentKey=keys?keys[index]:index;
memo=iteratee(memo,obj[currentKey],currentKey,obj);
}
returnmemo;
}

returnfunction(obj,iteratee,memo,context){
iteratee=optimizeCb(iteratee,context,4);
varkeys=!isArrayLike(obj)&&_.keys(obj),
length=(keys||obj).length,
index=dir>0?0:length-1;
if(arguments.length<3){
memo=obj[keys?keys[index]:index];
index+=dir;
}
returniterator(obj,iteratee,memo,keys,index,length);
};
}
_.reduce=_.foldl=_.inject=createReduce(1);
_.reduceRight=_.foldr=createReduce(-1);

//predicate为一个函数,遍历数组,若returntrue直接返回。里面用到一个_.findIndex函数,先研究下。研究在下面。
//_.findKey也差不多。最终函数返回obj[key];

_.find=_.detect=function(obj,predicate,context){
varkey;
if(isArrayLike(obj)){
key=_.findIndex(obj,predicate,context);
}else{
key=_.findKey(obj,predicate,context);
}
if(key!==void0&&key!==-1)returnobj[key];
};
//这个函数就是index搜索器,dir表示正者搜还是反着搜,搜到predicate函数返回的是ture的时候就把索引返回的,都没搜到就返回-1;
functioncreateIndexFinder(dir){
returnfunction(array,predicate,context){
predicate=cb(predicate,context);
varlength=array!=null&&array.length;
varindex=dir>0?0:length-1;
for(;index>=0&&index<length;index+=dir){
if(predicate(array[index],index,array))returnindex;
}
return-1;
};
}

_.findIndex=createIndexFinder(1);
//和前面那个差不多,不过返回键名
_.findKey=function(obj,predicate,context){
predicate=cb(predicate,context);
varkeys=_.keys(obj),key;
for(vari=0,length=keys.length;i<length;i++){
key=keys[i];
if(predicate(obj[key],key,obj))returnkey;
}
};

//把predicate返回为true的堆到一个新数组,再返回这个新数组
_.filter=_.select=function(obj,predicate,context){
varresults=[];
predicate=cb(predicate,context);
_.each(obj,function(value,index,list){
if(predicate(value,index,list))results.push(value);
});
returnresults;
};

//扩展自己,利用attrs类型的json,调用传入一个对象
_.matcher=_.matches=function(attrs){
attrs=_.extendOwn({},attrs);
returnfunction(obj){
return_.isMatch(obj,attrs);
};
};

//传对象和attrs,attrs类似{"a":1,"b":2}这种json的东西,若json类似的存在于obj中,则返回true,否则false;
_.isMatch=function(object,attrs){
varkeys=_.keys(attrs),length=keys.length;
if(object==null)return!length;
varobj=Object(object);
for(vari=0;i<length;i++){
varkey=keys[i];
if(attrs[key]!==obj[key]||!(keyinobj))returnfalse;
}
returntrue;
};
//遍历obj中的每一个值,返回一个数组,这个数组包含properties所列出的属性的所有的键值对。
//这里的obj是类[{},{},{}]的东西
_.where=function(obj,attrs){
return_.filter(obj,_.matcher(attrs));
};


//全部obj的元素分别调用predicate,有一个返回值是false,整个返回false
//否则返回true
_.every=_.all=function(obj,predicate,context){
predicate=cb(predicate,context);
varkeys=!isArrayLike(obj)&&_.keys(obj),
length=(keys||obj).length;
for(varindex=0;index<length;index++){
varcurrentKey=keys?keys[index]:index;
if(!predicate(obj[currentKey],currentKey,obj))returnfalse;
}
returntrue;
};

//全部obj的元素分别调用predicate,有一个返回值是true,整个返回false
//否则返回false
_.some=_.any=function(obj,predicate,context){
predicate=cb(predicate,context);
varkeys=!isArrayLike(obj)&&_.keys(obj),
length=(keys||obj).length;
for(varindex=0;index<length;index++){
varcurrentKey=keys?keys[index]:index;
if(predicate(obj[currentKey],currentKey,obj))returntrue;
}
returnfalse;
};
//检查obj是否包含target,就是indexOf方法的调用。
_.contains=_.includes=_.include=function(obj,target,fromIndex){
if(!isArrayLike(obj))obj=_.values(obj);
return_.indexOf(obj,target,typeoffromIndex=='number'&&fromIndex)>=0;
};

//对每个obj元素调用method,注意method方法的获取,例子用了[]['sort'],获取到sort函数引用
//args,是传给method的参数,可选。
_.invoke=function(obj,method){
varargs=slice.call(arguments,2);
varisFunc=_.isFunction(method);
return_.map(obj,function(value){
varfunc=isFunc?method:value[method];
returnfunc==null?func:func.apply(value,args);
});
};
_.invoke([[5,1,7],[3,2,1]],'sort');

//传key,获得值组成的数组。
_.pluck=function(obj,key){
return_.map(obj,_.property(key));
};
varstooges=[{name:'moe',age:40},{name:'larry',age:50},{name:'curly',age:60}];
_.pluck(stooges,'name');
//结果["moe","larry","curly"]

//普通的数组且没有传iteratee的情况下,直接用交换机的方式比较最大值
//传了迭代函数的话,一般obj是[{a:1},{a:2},{a:3}],迭代函数把各个对象的相应键的值取出来比较。再返回最大值
_.max=function(obj,iteratee,context){
varresult=-Infinity,lastComputed=-Infinity,
value,computed;
if(iteratee==null&&obj!=null){
obj=isArrayLike(obj)?obj:_.values(obj);
for(vari=0,length=obj.length;i<length;i++){
value=obj[i];
if(value>result){
result=value;
}
}
}else{
iteratee=cb(iteratee,context);
_.each(obj,function(value,index,list){
computed=iteratee(value,index,list);
if(computed>lastComputed||computed===-Infinity&&result===-Infinity){
result=value;
lastComputed=computed;
}
});
}
returnresult;
};

//用Fisher-Yatesshuffle算法,产生随机排序数组
//https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
_.shuffle=function(obj){
varset=isArrayLike(obj)?obj:_.values(obj);
varlength=set.length;
varshuffled=Array(length);
for(varindex=0,rand;index<length;index++){
rand=_.random(0,index);
//这里用交换机,rand<index的时候,把shuffled【rand】索引的值放到shuffled【index】索引上
if(rand!==index)shuffled[index]=shuffled[rand];
shuffled[rand]=set[index];
}
returnshuffled;
};

//guard默认是1,n==null的时候,默认随机返回一个obj数组元素
//n有值的时候,返回n个元素
_.sample=function(obj,n,guard){
if(n==null||guard){
if(!isArrayLike(obj))obj=_.values(obj);
returnobj[_.random(obj.length-1)];
}
return_.shuffle(obj).slice(0,Math.max(0,n));
};

//一般用来转换nodelist为真正的数组,可以调用原生的数组方法。
_.toArray=function(obj){
if(!obj)return[];
if(_.isArray(obj))returnslice.call(obj);
if(isArrayLike(obj))return_.map(obj,_.identity);
return_.values(obj);
};

//数组的长度或者对象键集合的长度。
_.size=function(obj){
if(obj==null)return0;
returnisArrayLike(obj)?obj.length:_.keys(obj).length;
};
//obj每个元素分别调用predicate,返回true的扔到pass数组,false的扔到fail数组
_.partition=function(obj,predicate,context){
predicate=cb(predicate,context);
varpass=[],fail=[];
_.each(obj,function(value,key,obj){
(predicate(value,key,obj)?pass:fail).push(value);
});
return[pass,fail];
};
集合的函数差不多就这些,其实还有4个函数,觉得用不太到还挺难就不写了,哈哈哈哈哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: