Undersocre 源码学习

简介: underscore 源码学习及注释

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 = {
  "&":"&amp;",
  "<":"&lt;",
  ">":"&gt;",
  '"':"&quot;",
  "'":"&#x27",
  "'":"&#x60;"
};
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 _;
})
}





目录
相关文章
|
6月前
|
NoSQL Java 应用服务中间件
关于阅读源码
【1月更文挑战第12天】关于阅读源码
|
缓存 算法 安全
程序员写代码为什么要阅读源码?
阅读一篇技术文章,畅聊一个技术话题。本期文章推荐的是《Node 中的 AsyncLocalStorage 的前世今生和未来》,一起来聊聊开发者阅读源码的这件事。阅读源码的过程实质上是对软件构建技术和架构深度的一种持续学习和理解。阅读源码可以揭示代码的内在逻辑,可以对技术深度的理解,也能提高对技术的理解程度。然而,仅仅阅读源码并不能代替实践操作,因为通过实践,可以更加全面的理解代码的深度和进展。
150 1
|
消息中间件 网络协议 Java
eventMesh源码学习
eventMesh源码学习
200 0
|
安全 Java
ReentranLock源码学习
线程的三大特性:原子性、可见性、有序性。也就是说满足这个三个特性的操作都是可以保证安全的,如Atomic包、volatile、通过happensBefore原则可以进行线程的安全的判断,这个依据通常是为了避免jvm指令重排。比如通常我们知道的配置信息,如果有多个线程去进行配置信息的修改,则需要进行上锁。或者多个线程修改一个变量时,此时就需要进行上锁了,或者读写分离时,可以考虑ReentrantReadWriteLock等。其本质是解决并行中的问题,将并行转成串行问题进行解决。那怎么上锁才有用呢?锁的状态大部分情况下是互斥的。当然也有特例:ReentrantReadWriteLock的读读是不会
95 0
ReentranLock源码学习
|
设计模式 分布式计算 资源调度
如何阅读源码
如何阅读源码
211 0
|
存储 人工智能 安全
C++学习必备——文章中含有源码
C++学习必备——文章中含有源码
120 0
C++学习必备——文章中含有源码
|
算法 Java 中间件
阅读优秀项目源码很重要,分享一个读源码的方法,小白都能学会
作为一个程序员,经常需要读一些开源项目的源码。同时呢,读源码对我们也有很多好处: 1.提升自己 2.修复 Bug 3.增加新功能
阅读优秀项目源码很重要,分享一个读源码的方法,小白都能学会

相关实验场景

更多