Undersocre 源码学习
(function(
//建立根元素,在浏览器中的window,或者exports在服务器上
var root = this;
//保存之前的_变量
var previousUnderscore = root._;
//最小地保存字节(不是gzip压缩)的版本
var ArrayProto = Array.prototype,ObjectProto =
Object.prototype,FuncProto = Function.prototype;
//创建快捷的引用变量,用于快速地访问核心的原型
var
push = ArrayProto.push,
slice = ArrayProto.slice,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
//所有ECMAScript 5,我们希望使用的本地函数实现都定义在这里了
var
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind,
nativeCreate = Object.create;
//空的函数应用,用于封装代理原型。
var Ctor = function(){};
//创建一个Underscore对象的安全引用,用于下面的使用。
var _ = function(obj){
if( obj instanceof _ ) return obj;
if( !( this instanceof _)) return new _(obj);
this._wrapped = obj;
};
//为Node.js导出Underscore的对象,向后兼容老的
//require() API。如果我们在我们是在浏览器中,添加
//_作为全局的对象
if( typeof exports !== "undefined"){
if( typeof module !== "undefined" && module.exports){
exports = module.exports = _;
}
exports._ = _;
}else{
root._ = _;
}
//当前版本
_.VERSION = "1.8.3";
//内部的函数会返回一个有效的回调函数(对于当前的库来说)
//这个是会在其它的Underscore函数中反复被应用的
var potimizeCb = function( func,context,argCount ){
if( context === void 0) return func;
switch( argCount == null ? 3 : argCount){
case 1: return function( value ){
return func.call( context,value);
};
case 2: return function(value,other){
return func.call(context,value,other)
};
case 3:return function(value,index,collection){
return func.call(context,value,index,collection);
};
case 4:return function(accumulator,value,index,collection){
return func.call(context,accumulator,value,index,collection);
}
return function(){
return func.apply(context,arguments);
}
}
}
//一个使用频繁的函数,用于生成回调,可以被应用在一个集合中的任一
//元素,返回预期的结果-可能是一个identity,或者一个任意的回调,一
//一个属性的匹配,或者一个属性的访问器
var cb = function(value,context,argCount){
if(value == null) return _.identity;
if(_.isFunction(value)) return potimizeCb(value,context,argCount);
if(_.isObject(value)) return _.matcher(value);
return _.property(value);
};
_.iteratee = function(value,context){
return cb(value,context,Infinity);
}
//一个内部的函数,用于创建分配函数
var createAssigner = function(keysFunc,undefinedOnly){
return function(obj){
var length = arguments.length;
if( length<2 || obj == null) return obj;
for(var index =1;index < length; index++ ){
var source = arguments[index],
keys = keysFunc(source),
l = keys.length;
for(var i=0; i< l; i++){
var key = keys[i];
if(!undefinedOnly || obj[key] === void 0)
obj[key] = source[key];
}
}
return obj;
};
};
var baseCreate = function(prototype){
if(!_.isObject(prototype)) return {};
if(nativeCreate) return nativeCreate(prototype);
Ctor.prototype = prototype;
var retuslt = new Ctor;
Ctor.prototype = null;
return result;
};
var property = function(key){
return function(obj){
return obj == null ? void 0:obj[key];
};
};
//集合方法的帮助器,用于确定一个集合是应该被作为数据或者对象
//遍历。http://people.mozilla.org/~jorendorff/es6-
//draft.html#sec-tolength Avoids a very nasty iOS 8 JIT bug on
//ARM-64. #2094
var MAX_ARRAY_INDEX = Math.pow(2,53) - 1;
var getLength = property("length");
var isArrayLike = function(collection){
var length = getLength(collection);
return typeof length == "number" && length >=0 && length <= MAX_ARRAY_INDEX;
};
//奠基石,一个each实现,同样被称为forEach.除了处理类似数组的
//数据,还处理一些原始数据。将所有稀疏数组当作密集的数组。
_.each = _.forEach = function(obj,iteratee,context){
iteratee = optimizedCb(iteratee,context);
var i,length;
if(isArrayLike(obj)){
for(i=0,length = obj.length;i<length;i++){
iteratee(obj[i],i,obj);
}
}else{
var keys = _.keys(obj);
for(i=0,length = keys.length;i<length;i++){
iteratee(obj[keys[i]],keys[i],obj);
}
}
return obj;
}
//返回所有应用了迭代器的结果到各个元素中
_.map = .collect = function(obj,iteratee,context){
iteratee = cb(iteratee,context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys || obj).length,
results = Array(length);
for(var index = 0; index < length; index++){
var currentKey = keys ? keys[index]:index;
results[index] = iteratee(obj[currentKey],currentKey,obj);
}
return results;
}
//创建一个reducing函数,从左到右迭代
//优化迭代器函数,在主函数中使用arguments.length
function createReduce(dir){
function iterator(obj,iteratee,memo,keys,index,length){
for(;index >= 0&& index<length;index+=dir){
var currentKey = keys ? keys[index]:index;
memo = iteratee(memo,obj[currentKey],currentKey,obj);
}
return memo;
}
return function(obj,iteratee,memo,context){
iteratee = optimizeCb(iteratee,context,4);
var keys = !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;
}
return iterator(obj,iteratee,memo,keys,index,length);
};
}
//Reduce从一系列值中构建一个单一的结果,正如inject,说这foldl
_.reduce = _.foldl = _.inject = createReduce(1);
//右结合的版本的reduce, 同样也称作foldr
_reduceRight = _.foldr = createReduce(-1);
//返回第一个通过真测试的值,别称为detect。
_.find = _.detect = function(obj,predicate,context){
var key;
if(isArrayLike(obj)){
key = _.findIndex(obj,predicate,context);
}else{
key = _.findKey(obj,predicate,context);
}
if(key !== void 0 && key !== -1) return obj[key];
}
//返回所有通过真测试的元素,别名为选择。
_.filter = _.select = function(obj,predicate,context){
var results = [];
predicate = cb(predicate,context);
_.each(obj,function(value,index,list){
if(predicate(value,index,list)) result.push(value);
});
return results;
}
// 返回所有真测试失败的元素
_.reject = function(obj,predicate,context){
return _.filter(obj,_.negate(cb(predicate)),context);
}
//确定是否所有的元素都匹配一个真测试。别称为all.
_.every = _.all = function(obj,predicate,context){
predicate = cb(predicate,context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys||obj).length;
for(var index = 0; index < length; indext++){
var currentKey = keys? keys[index] : index;
if(!predicate(obj[currentKey],currentKey,obj)) return false;
}
return true;
}
//确认是否至少在对象中的一个元素匹配了一次真测试。别称为any.
_.some = _.any = function(obj,predicate,context){
predicate = cb(predicate,context);
var keys = !isArrayLike(obj) && _.keys(obj),
length = (keys||obj).length;
for(var index =0;index < length; index++){
var currentKey = keys? keys[index]:index;
if(predicate(obj[currentKey],currentKey,obj)) return true;
}
return false;
}
//确定是否数组或者对象包含一个给定的项(使用===).别称为include
//和include
_.contians = _.includes = _.include = function(obj,item,fromIndex,guard){
if(!isArrayLike(obj)) obj = _.value(obj);
if(typeof fromIndex != 'number' || guard ) fromIndex = 0;
return _.indexOf(obj,item,fromIndex) >=0;
}
//调用一个方法(带参数)在一个集合的每一个项目中。
_.invoke = function(obj,method){
var args = slice.call(arguments,2);
var isFunc = _.isFunction(method);
return _.map(obj,function(value){
var func = isFunc ?method :value[method];
return func == null ? func :func.apply(value,args);
})
}
_.pluck = function(obj,key){
return _.map(obj,_.property(key));
}
_.where = function(obj,attrs){
return _.filter(obj,_matcher(attrs));
}
_.findWhere = function(obj,attrs){
return _.find(obj,_.matcher(attrs));
}
_.max = function(obj,iteratee,context){
var result = -Infinity,lastComputed = -Infinity,value,computed;
if(iteratee == null && obj != null){
obj = isArrayLike(obj) ? obj :_.values(obj);
for(var i =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;
}
});
}
return result;
}
_.min = function(obj,iteratee,context){
var result = Infinity,lastComputed = Infinity,value,computed;
if(iteratee == null && obj != null){
obj = isArrayLike(obj) ? obj :_.values(obj);
for(var i = 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;
}
});
}
return result;
};
_.shuffle = function(obj){
var set = isArrayLike(obj) ? obj :_.values(obj);
var length = set.length;
var shuffled = Array(length);
for(var index = 0,rand; index < length; index++){
rand = _.random(0,index);
if(rand !== index) shuffled[index] = shuffled[rand];
shuffled[rand] = set[index];
}
return shuffled;
}
_.sample = function(obj,n,guard){
if(n == null || guard){
if(!isArrayLike(obj)) obj = _.values(obj);
return obj[_.random(obj.length - 1 )];
}
return _.shuffle(obj).slice(0,Math.max(0,n));
}
_.sortBy = function(obj,iteratee,context){
iteratee = cb(iteratee,context);
return _.pluck(_.map(obj,function(value,index,list){
return {
value:value,
index:index,
criteria:iteratee(value,index,list)
};
}).sort(function(left,right){
var a = left.criteria;
var b = right.criteria;
if(a !== b ){
if(a > b || a === void 0 ) return 1;
if(a < b || b === void 0 ) return -1;
}
return left.index = right.index;
}),'value');
};
var group = function(behavior){
return function(obj,iteratee,context){
var result = {};
iteratee = cb(iteratee,context);
_.each(obj,function(value,index){
var key = iteratee(value,index,obj);
behavior(result,value,key);
});
return result;
};
};
_.groupBy = group(function(yresult,value,key){
if(_.has(result,ke))
result[key].push(value);
else
result[key] = [value];
});
_.indexBy = group(function(result,value,key){
if(_.has(result,key)) result[key].push(value);
});
_.countBy = group(function(result,value,key){
if(_.has(result,key)) result[key]++; else result[key] = 1;
});
_.toArray = function(obj){
if(!obj) return [];
if(_.isArray(obj)) return slice.call(obj);
if(isArrayLike(obj)) return _.map(obj,_.identity);
return _.values(obj);
}
_.size = function(obj){
if(obj == null) return 0;
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
}
_.partition = function(obj,predicate,context){
predicate = cb(predicate,context);
var pass = [],fail = [];
_.each(obj,function(value,key,obj){
(predicate(value,key,obj) ? pass:fail).push(value);
});
return [pass,fail];
};
_.first = _.head = _.take = function(array,n,guard){
if(array == null) return void 0;
if(n == null || gurad) return array[0];
return _.initial(array,array.length-n);
}
_.initial = function(array,n,guard){
return slice.call(array,0,Math.max(0,array.length-(n == null || gurad ? 1: n)));
}
_.last = function(array,n,guard){
if(array == null ) return void 0;
if( n==null || guard ) return array[array.length -1 ];
return _.rest(array,Math.max(0,array.length - n));
}
_.rest = _.tail = _.drop = function(array,n,guard){
return slice.call(array,n == null||guard ? 1: n);
}
_.compact = function(array){
return _.filter(array,_.identity);
}
var flatten = function(input,shallow,strict,startIndex){
var output = [],indx = 0;
for(var i=startIndex||0,length = getLength(input);i < length; i++){
var value = input[i];
if(isArrayLike(value) && (_.isArray(value)||_.isArguments(value))){
if(!shallow) value = flatter(value,shallow,strict);
var j = 0,len = value.length;
output.length + = len;
while( j < len){
output[idx++] = value[j++];
}
}else if(!strict){
output[idx++] = value;
}
}
return output;
}
_.flatten = function(array,shallow){
return flatten(array,shallow,false);
}
_.without = function(array){
return _.difference(array,slice.call(arguments,1))
}
_.uniq = _.unique = function(array,isSorted,iteratee,context){
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){
if(!i || seen !== computed) result.push(value);
seen = computed;
}else if(iteratee){
if(!_.contains(seen,computed)){
seen.push(computed);
result.push(value);
}else if( !_.contains(result,value)){
result.push(value);
}
}
return result;
}
}
_.union = function(){
return _.uniq(faltten(arguments,true,true));
}
_.intersection = function(array){
var result = [];
var argsLength = arguments.length;
for(var i =0,length = getLength(array);i < length;i++){
var item = array[i];
if(_.contains(result,item)) continue;
for(var j = 1;j < argsLength; j++){
if(!_.contiains(arguments[j],item)) break;
}
if(j === argsLength ) result.push(item);
}
return result;
};
_.differenct = function(array){
var rest = flatten(arguments,true,true,1);
return _.filter(array,function(value){
return !_.contains(rest,value);
});
}
_.zip = function(){
return _.unzip(arguments);
}
_.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;
}
_.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][0];
}
}
return result;
}
function createPredicateIndexFinder(dir){
return function(array,predicate,context){
predicate = cb(predicate,context);
var length = getLength(array);
var index = dir > 0 ? 0 : length - 1;
for(;index >= 0 && index < length; index += dir){
if(predicate(array[index],index,array)) return index;
}
return -1;
}
}
_.findIndex = createPredicateIndexFinder(1);
_.findLastIndex = createPredicateIndexFinder(-1);
_.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;
};
function createIndexFinder(dir,predicatedFind,sortedIndex){
return function(array,item,idx){
var i = 0,length = getLength(array);
if( typeof idx == "number"){
if(dir > 0 ){
i = idx >= 0 ? idx : Math.max(idx + length,i);
}else{
length = idx >=0 ? Math.min(idx + 1,length) :idx + length +1;
}
}else if(sortedINdex && idx && length){
idx = sortedIndex(array,item);
return array[idx] === item ? idx : -1;
}
if(item !== item){
idx = predicateFind(slice.call(array,i,length),_.isNaN);
return idx > =0 ? idx + i : -1;
}
for(idx = idr > 0 ? i : length -1; idx >=0 && idx < length; idx+=dir){
if(array[idx] === item) return idx;
}
return -1;
};
}
_.indexOf = createIndexFinder(1,_.findIndex,_.sortedIndex);
_.lastIndexOf = createIndexFinder(-1,_.findLastIndex);
_.range = function(start,stop,step){
if(stop == null){
stop = start || 0;
start = 0;
}
step = step || 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;
}
var executeBound = function(sourceFunc,boundFunc,context,callingContext,args){
if(!(callingContext instanceof boundFunc)) return sourceFunc.apply(context,args);
var self = baseCreate(sourceFunc.prototype);
var result = sourceFunc,apply(self,args);
if(_.isObject(result)) return result;
return self;
}
_.bind = function(func,context){
if(nativeBind && func.bind === nativeBind)
return nativeBind.apply(func,slice.call(arguments,1));
if(! _.isFunction(func)) throw new TypeError("Bind must be called on a function");
var args = slice.call(arguments,2);
var bound = function(){
return executeBound(func,bound,context,this,args.concat(slice.call(arguments)));
return bound;
}
}
_.partial = function(func){
var boundArgs = slice.call(arguments,1);
var bound = function(){
var position = 0 ,length = boundArgs.length;
var args = Array(length);
for(var i = 0; i< length; i++){
args[i] = boundArgs[i] == _ ? arguments[position++] : boundArgs[i];
while( position < arguments.length) args.push(arguments[position++])
return executeBound(func,bound,this,this,args)
};
return bound;
}
}
_.bindAll = function(obj){
var i,length = arguments.length,key;
if(length <=1 ) throw new Error("bindAll must be passed function names");
function(i=1; i < length; i++){
key = arguments[i];
obj[key] = _.bind(obj[key],obj);
}
return obj;
}
_.memorize = function(func,hasher){
var memorize = function(key){
var cache = memorize .cache;
var address = "" + ( hasher ? hasher.apply(this.arguments):key);
if(!_.has(cache,address)) cache[address] = func.apply(this.arguments);
return cache[address];
};
memorize.cahce = {};
return memorize;
};
_.delay = funciton(func,wait){
var args = slice.call(arguments,2);
return setTimeout(function(){
return func.apply(null,args);
},wait)
}
_.defer = _.partial(_.delay,_,1);
_.throttle = function(func,wait,options){
var context,args,result;
var timeout = null;
var previous = 0;
if(!options) options = {};
var later = function{
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context,args);
if(!timeout) context = args = null;
};
return function(){
var now = _.now();
if(!previous && options.leading === false) previous = now;
var remaining = wait - ( now - previous);
context = this;
args = arguments;
if(remaining <= 0 || remaining > wait){
if(timeout){
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context,args);
if(!timeout) context = args = null;
}else if(!timeout && options.trailing !== false){
timeout = setTimeout(later,remaining);
}
return resul;
};
};
_.debounce = function(func,wait,immediate){
var timeout,args,context,timesstamp,result;
var later = function(){
var last = _.now() - timestamp;
if(last < wait && last >= 0 ){
timeout = setTimeout(later,wait - last);
}else{
timeout = null;
if(!immediate){
result = func.apply(context,args);
if(!timeout) context = args = null;
}
}
};
return function(){
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
if(!timeout) timeout = setTimeout(later,wait);
if(casllNow){
result = func.apply(context,args);
context = args = null;
}
return result;
};
};
_.wrap = function(func,wrapper){
return _.partial(wrapper,func);
}
_.negate = function(predicate){
return function(){
return !predicate.apply(this,arguments);
}
}
_.compose = function(){
var args = arguments;
var start = args.length -1 ;
return function(){
var i = start;
var result = args[start].apply(this,arguments);
while(i--) result = args[i].call(this,result);
return result;
}
}
_.after = function(times,func){
return function(){
if(--times < 1){
return func.apply(this,arguments);
}
}
}
_.before = function(times,func){
var memo;
return function(){
if(--times > 0){
memo = func.apply(this,arguements);
}
if(times <=1 ) func = null;
return memo;
}
}
_.once = _.partial(_.before,2);
var hasEnumBug = !{toString:null}.propertyIsEnumberable("toString");
var nonEnumberableProps = ["valueOf","isPrototypeOf","toString",
"propertyIsEnumerable","hasOwnProperty","toLocalString"
];
function collectionNonEnumProps(obj,keys){
var nonEnumIdx = nonEnumerableProps.length;
var constructor = obj.constructor;
var proto = {_.isFunction(constructor) && constructor.prototype }|| ObjProto;
var prop = "constructor";
if(_.has(obj,prop) && !_.contains(keys,prop)) keys.push(prop);
while(nonEnumIdx--){
prop = nonEnumerableProps[nonEnumIdx];
if(prop in obj && obj[prop] !== proto[porp] && !_.contains(keys,prop)){
keys.push(prop);
}
}
}
_.keys = function(obj){
if(!_.isObject(obj)) return [];
if(nativeKeys) return nativeKeys(obj);
var keys = [];
for(var key in obj) if(_.has(obj,key)) keys.push(key);
if(hasEnumBug) collecNonEnumProps(obj,keys);
return keys;
}
_.allKeys = function(obj){
if(!_.isObject(obj)) return [];
var keys = [];
for(var key in obj ) keys.push(key);
if(hasEnumBug) collectNonEnumProps(obj,keys);
return keys;
}
_.values = function(obj){
var keys = _.keys(obj);
var length = keys.length;
var values = Array(length);
for(var i = 0 ; i < length; i++){
values[i] = obj[keys[i]];
}
return values;
}
_.mapObject = function(obj,iteratee,context){
iteratee = cb(iteratee,context);
var keys = _.keys(obj),
length = keys.length,
results = {},
currentKey;
for(var index = 0; index < length; index++){
currentKey = keys[index];
results[currentKey] = iteratee(obj[currentKey],currentKey,obj);
}
return results;
}
_.pairs = function(obj){
var keys = _.keys(obj);
var length = keys.length;
var pairs = Array(length);
for(var i = 0; i < length; i++){
pairs[i] = [keys[i],obj[keys[i]]];
}
return pairs;
}
_.invert = function(obj){
var result = {};
var keys = _.keys(obj);
for(var i = 0 ,length = keys.length;i < length; i++){
result[obj[keys[i]]] = keys[i];
}
return result;
}
_.functions = _.methods = function(obj){
var names = [];
for(var key in obj){
if(_.isFunction(obj[key])) names.push(key);
}
return names.sort();
}
_.extend = createAssigner(_.allKeys);
_.extendOwn = _.assign = createAssigner(_.keys);
_.findKey = function(obj,predicate,context){
predicate = cb(predicate,context);
var keys = _.keys(obj),key;
for(var i = 0, length = keys.length; i < length; i++){
key = keys[i];
if(predicate(obj[key],key,obj)) return key;
}
}
_.pick = function(obj,oiteratee,context){
var result = {},obj = object,iteratee,keys;
if(obj == null ) return result;
if(_.isFunction(oiteratee)){
keys = _.allKeys(obj);
iteratee = optimizeCb(oiteratee,context);
}else{
keys = flatten(arguments,false,false,1);
iteratee = function(value,key,obj){ return key in obj;};
obj = Object(obj);
}
for(var i = 0, length = keys.length; i < length; i++){
var key = keys[i];
var value = obj[key];
if(iteratee(value,key,obj)) result[key] = value;
}
return result;
}
_.omit = function(obj,iteratee,context){
if(_.isFunction(iteratee)){
iteratee = _.negate(iteratee);
}else{
var keys = _.map(flatter(arguments,false,false,1),String);
iteratee = function(value,key){
return !_.contains(keys,key);
}
}
return _.pick(obj,iteratee,context);
}
_.defaults = createAssigner(_.allKeys,true);
_.create = function(prototype,props){
var result = baseCreate(prototype);
if(props) _.extendOwn(result,props);
return result;
}
_.clone = function(obj){
if(!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({},obj);
}
_.tap = function(obj,interceptor){
interceptor(obj);
return obj;
}
_.isMatch = function(object,attrs){
var keys = _.keys(attrs),length = keys.length;
if(object == null ) return !length;
var obj = Object(object);
for(var i = 0; i < length; i++){
var key = keys[i];
if(attrs[key] !== obj[key] || !(key in obj)) return false;
}
return true;
}
var eq = function(a,b,sStack,bStack){
if(a === b) return a !== 0 || 1/a === 1/b;
if(a == null || b == null ) return a === b;
if(a instanceof _ ) a = a._wrapped;
if(b instanceof _) b = b._wrapped;
var className = toString.call(a);
if(className !== toString.call(b)) return false;
switch(className){
case "[object RegExp]":
case "[object String]":
return "" + a === "" + b ;
case "[object Number]":
if(+a !== +a) return +b !== +b;
return +a === 0 ? 1/+a === 1/b : +a === +b;
case "[object Date]":
case "[object Boolean]":
return +a === +b'
}
var areArrays = className == "[object Array]";
if(!areArrays){
if(typeof a != "object"|| typeof b != "object") return false;
var aCtor = a.constructor,bCtor = b.construct;
if(aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && _.isFunction(bCtor) && bCtor instanceof bCtor && ("constructor" in a && "constructor" in b)))
return false;
}
}
aStack = aStack ||[];
bStack = bStack || [];
var length = aStack.length;
while(length--){
if(aStack[length] === a) return bStack[length] === b;
}
aStack.push(a);
bStack.push(b);
if(areArrays){
length = a.length;
if(length !== b.length ) return false;
while(length--){
if(!eq(a[length],b[length],aStack,bStack)) return false;
}else{
var keys = _.keys(a),key;
length = keys.length;
if(_.keys(b).length !== length) return false;
while(length--){
key = keys[length];
if(!(_.has(b,key)&&eq(a[key],b[key],aStack,bStack))) return false;
}
}
aStack.pop();
bStac,.pop();
return true;
}
_.isEqual = function(a,b){
return eq(a,b);
}
_.ieEmpty = function(obj){
if(obj == null ) return true;
if(isArrayLike(obj) && (_.isArray(obj)||_.isString(obj)||_.isArguments(obj)))
return obj.length === 0;
return _.keys(obj).length === 0;
}
_isElement = function(obj){
return !!(obj && obj.nodeType ===1 );
}
_.isArray = nativeIsArray || function(obj){
return toString.call(obj) == "[object Array]";
}
_.isObject = function(obj){
var type = typeof obj;
return type === "function" || type === "object" && !!obj;
}
_.each(["Argument","Function","String","Number","Date","RegExp","Error"],function(name){
_["is" + name] = function(obj){
return toString.call(obj) === "[object" + name + "]";
};
});
if(!_.isArguments(arguments)){
_.isArguments = function(obj){
return _.has(obj,"callee");
}
}
if( typeof /./ != "function" && typeof Int8Array != "object"){
_.isFunction = function(obj){
return typeof obj == "function" || false;
}
}
_.isFinite = function(obj){
return isFinite(obj) && !isNaN(parseFloat(obj));
}
_.isNaN = function(obj){
return _.isNumber(obj) && obj !== +obj;
}
_.isBoolean = function(obj){
return obj === true || obj === false || toString.call(obj) === "[object Boolean]"
}
_.isNull = function(obj){
return obj === null;
}
_.isUndefined = function(obj){
return obj === void 0;
}
_.has = function(obj,key){
return obj != null && hasOwnProperty.call(obj,key);
}
_.noConflict = function(){
root._ = previousUnderscore;
return this;
}
_.identity = function(value){
return value;
}
_.constanct = function(value){
return function(){
return value;
}
}
_.noop = function(){};
_.property = property;
_.propertyOf = function(obj){
return obj == null ? function(){} : function(key){
return obj[key];
};
};
_.matcher = _.matches = function(attrs){
attrs = _.extendOwn({},attrs);
return function(obj){
return _.isMatch(obj,attrs);
}
}
_.times = function(n,iteratee,context){
var accum = Array(Math.max(0,n));
iteratee = optimizeCb(iteratee,context,1);
for(var i = 0 ; i< n; i++) accum[i] = iteratee[i];
return accum;
}
_.random = function(min,max){
fi(max == null){
max = min;
min = 0;
}
return min + Math.floor(Math.random()*(max-min+1));
}
_.now = Date.now || function(){
return new Date().getTime();
};
var escapeMap = {
"&":"&",
"<":"<",
">":">",
'"':""",
"'":"'",
"'":"`"
};
var unescapeMap = _.invert(escapeMap);
var createEscaper = function(map){
var escaper = function(match){
return map[match];
}
var source = "(?:" + _.keys(map).join("|") + ")";
var testRegexp = RegExp(source);
var replaceRegexp = RegExp(source,"g");
return function(string){
string = string == null ? "" : "" + string;
return testRegexp.test(string) ? string.replace(replaceRegexp,escaper):string;
};
};
_.escape = createEscaper(escapeMap);
_.unescape = createEscaper(unescapeMap);
_.result = function(object,property,fallback){
var value = object == null ? void 0 : object[property];
if(value == void 0){
value = fallback
}
return _.isFunction(value) ? value.call(object):value;
}
var idCounter = 0 ;
_.uniqueId = function(prefix){
var id = ++idCounter + "";
return prefix ? prefix + id :id;
}
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate:/<%=([\s\S]+?)%>/g,
escape:/<%-([\s\S+?])%>/g
};
var noMatch = /(.)^/;
var escapes = {
"'": "'",
'\\': '\\',
"\r":'r',
"\n":'n',
'\u2028':'u2028',
'\u2029':'u2029'
};
var escaper = /\\|'|\r|\n|\u2018|\u2029/g;
var escapeChar = function(match){
return '\\' + ecapes[match];
}
_.template = function(text,settings,oldSettings){
if(!settings && oldSettings) = settings = oldSettings;
settings = _.defaults({},settings,_.templateSettings);
var matcher = RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join("|") + '|$',"g");
var index = 0;
var source = "__p+=";
text.replace(matcher,function(match,escape,interpolate,evaluate,offset){
source += text.slice(index,offset).replace(escaper,escapeChar);
index = offset + match.length;
if (escape){
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t)+\n";
}else if(interpolate){
source += "'+\n((__t=(" + interpolate + "))==null?'':_t)+\n'";
}else if(evaluate){
source += "';\n" + evaluate + "\n__p+=";
}
return match;
});
source += "';\n";
if(!settings.variable srouce = "with(obj||{}){\n" + source + "}\n";
source = "var __t,__p='',__j=Array.prototype.join,"+
"print=function(){__p+=__j.call(arguments,"");};\n" + source + "return __p;\n";
try{
var render = newFunction(settings.variable || "obj","_",source);
}catch(e){
e.source = source;
throw e;
}
var template = function(data){
return render.call(this.data,_);
}
var argument = settings.variable || "obj";
template.source = "function(" + argument + ")}\n" + source + "
]";
return template;
}
_.chain = function(obj){
var instance = _(obj);
instance._chain = true;
return instance;
}
var result = function(instance,obj){
return instance._chain ? _(obj).chain():obj;
}
_.mixin = function(obj){
_.each(_.functions(obj),function(name){
var func = _[name] = obj[name];
_.prototype[name] = function(){
var args = [this._wrapped];
push.apply(args,arguments);
return result(this,func.apply(_,args));
}
})
};
_.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);
if( (name === "shift")||name === "splice")&& obj.length === 0) delete obj[0];
return result(this,obj);
};
});
_.each(["contact","join","slice"],fuction(name){
var method = ArrayProto[name];
_.prototype[name] = function(){
return result(this,method.apply(this._wrapped,arguments));
}
});
_.prototype.value = function(){
return this._wrapped;
}
_.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
_.prototype.toString = function(){
return "" + this._wrapped;
};
if(typeof define === "function" && define.amd){
define("underscore",[],function(){
return _;
})
}