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





目录
相关文章
|
3月前
|
消息中间件 Java 测试技术
Goim框架的源码学习笔记
Goim框架的源码学习笔记
|
7月前
|
NoSQL Java 应用服务中间件
关于阅读源码
【1月更文挑战第12天】关于阅读源码
|
JavaScript
源码
源码
|
程序员 开发工具 C++
|
消息中间件 网络协议 Java
eventMesh源码学习
eventMesh源码学习
212 0
|
安全 Java
ReentranLock源码学习
线程的三大特性:原子性、可见性、有序性。也就是说满足这个三个特性的操作都是可以保证安全的,如Atomic包、volatile、通过happensBefore原则可以进行线程的安全的判断,这个依据通常是为了避免jvm指令重排。比如通常我们知道的配置信息,如果有多个线程去进行配置信息的修改,则需要进行上锁。或者多个线程修改一个变量时,此时就需要进行上锁了,或者读写分离时,可以考虑ReentrantReadWriteLock等。其本质是解决并行中的问题,将并行转成串行问题进行解决。那怎么上锁才有用呢?锁的状态大部分情况下是互斥的。当然也有特例:ReentrantReadWriteLock的读读是不会
97 0
ReentranLock源码学习
|
设计模式 分布式计算 资源调度
如何阅读源码
如何阅读源码
218 0
|
存储 人工智能 安全
C++学习必备——文章中含有源码
C++学习必备——文章中含有源码
122 0
C++学习必备——文章中含有源码
|
算法 Java 中间件
阅读优秀项目源码很重要,分享一个读源码的方法,小白都能学会
作为一个程序员,经常需要读一些开源项目的源码。同时呢,读源码对我们也有很多好处: 1.提升自己 2.修复 Bug 3.增加新功能
阅读优秀项目源码很重要,分享一个读源码的方法,小白都能学会
|
算法 NoSQL 前端开发
为什么要看源码、如何看源码,高手进阶必看
为什么要看源码、如何看源码,高手进阶必看
276 0

相关实验场景

更多