Skip to content

underscore bind,object.keys,Array.isArray等es5源码

Published: at 12:00 AM


借用underscore的bind方法的源码实现
示例:

    var func = function (greeting) {
      return greeting ":" this.name;
    }
    func = _.bind(func, {name:joe}, Hi);
    func();  // Hi : joe


源码:
通用准备:

    var optimizeCb= 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.call(context, arguments)
      }
    }
    var cb = function(value, context, argCount) {
      if (value == null) return _.identity;
      if (_.isFunction(value)) return optimizeCb(value, context, argCount);
      if (_.isObject(value)) return _.matcher(value);
      return _.property(value);
    };


    var slice = array.prototype.slice;
        nativebind = Function.prototype.bind;
    _.isFunction = fucntion(obj) {
      return typeof obj === 'function' || false;
    }
    _.isObject = function(obj){
      return typeof obj === object || function;
    }
    _.baseCreate = function(prototype){
      var func = function(){};
      func.prototype = prototype;
      return new func;
    }
    var executeBound = function(sourceFunc,boundFunc,context,callingContext,args){
      if (! callingContext instanceOf boundFunc) return sourceFunc.apply(context,args);
      var Func1 = _.baseCreate(sourceFunc.prototype);
      var result = sourceFunc.apply(Func1,args);
      if (_.isObject(result)) return result;
      return Func1;
    }
    _bind = function(func, context){
      if (nativebind && func.bind === nativebind ){
        return nativebind.apply(func, slice.call(arguments,1))
      }
      if (!_.isFunction(func)){
        throw new TypeError("func must be a function");
      }
      var args = slice.call(arguments, 2);
      var bound = function(){
        return executeBound(func,bound,context,this,args.concat(slice.call(arguments));
      }
      return bound;
    }


object.keys源码

    object.keys = _.keys= function(obj){
      _.has = function(obj, key){
        return obj !==null && object.prototype.hasOwnProperty.call (obj, key);
      }
      if (!typeof obj === object) return [];
      if (object.keys) return object.keys(obj);
      var keys = [];
      for (var key in obj){
        if (_.has(obj, key)){
          keys.push(key);
        }
      }
      return keys;
    }


Array.isArray源码

    var nativeIsArray = Array.isArray,
        toString = Object.prototype.toString;
    _.isArray = nativeIsArray || function (arr){
        return toString.call(arr) === '[object Array]';
    }


indexOf源码

    _.sortedIndex = function(array, obj, iteratee, context){
      iteratee = cb(iteratee, context);
       var value = iteratee(obj);
       var low = 0, high=array.length;
       while(low < high){
         mid = Math.floor((low + high)/2);
         iteratee(array[mid]) < value ? low = mid+1 : high = mid;
       }
       return low;
    };
    _.findIndex = function(array, iteratee, context){
       predicate = cb(predicate, context);
       for (var i=0, length= array && array.length; i<length; i++ ){
         if (predicate(array[i], i, array)){
           return i;
         }
         return -1;
       }
    }
    _.indexOf = function(arr, item, isSorted){
      var i = 0; length = arr && arr.length;
      if (typeof isSorted == 'number'){
        i= isSorted>0?isSorted: Math.max(0,arr.length+isSorted);
      }else if (isSorted && length>0){
          i= _.sortedIndex(arr, item);
          return arr[i] === item ? i : -1;
      }
      if (item !== item){
        return _.findIndex(slice.call(arr, i), _.isNaN)
      }
      for (;i<length;i++){
        if (arr[i]===item) return i;
      }
      return -1;
    };


Array.prototype.every(t,c);

    var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
    var isArrayLike = function(collection){
      var length = collection && collection.length;
      typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
    }

    _.every = function(obj, iteratee, context){
      var predicate= cb(iteratee, 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 (!iteratee(obj[currentKey], currentKey, obj)) return false;
      }
      return true;
    }


Array.prototype.some(t,c);

    _.some = function(obj, iteratee, context){
      predicate = cb(iteratee, context);
      keys = !isArrayLike(obj) && _.keys(obj);
      length= (keys || obj).length;
      for (var index= 0; index< length; index++){
        currentKey= keys ? keys[index] : index;
        if (iteratee(obj[currentKey])) return true;
      }
      return false;
    }


Array.prototype.forEach(t,c);

    _.each= _.forEach= function(obj, iteratee, context){
      iteratee = optimizeCb(iteratee, context);
      //iteratee是函数。
      var keys= !isArrayLike(obj) && _.keys(obj);
      var length= (keys || obj).length;
      for (var i= 0; i< length; i++){
        var currentKey= keys ? keys[i] : i;
        iteratee(obj[currentKey], currentKey, obj);
      }
      return obj;
    };


Array.prototype.map(f,c)

    _.map= function(obj, iteratee, context){
      iteratee = cb(iteratee, context);
      //iteratee可以是null,函数,对象。
      var keys= !isArrayLike(obj) && _.keys(obj);
      var length= (keys || obj).length;
      var array= Array(length);
      for (var i= 0; i< length; i++){
        var currentKey= keys ? keys[i] : i;
        array[i]= iteratee(obj[currentKey], currentKey, obj);
      }
      return array;
    };


Array.prototype.filter(f,c)

    _.filter= _.select= function(obj, iteratee, context){
      var predicate= cb(iteratee, context);
      var results= [];
      _.each(obj,function(value, index, list){
        if (predicate(value, index, list)) results.push(value);
      });
      return results;
    };


Array.prototype.reduce(f,c)

    function createReduce(dir){
      function iterator(obj, iteratee, memo, keys, index, length){
         for (; index >= 0 && index < length; index += dir){
           var currentKey= keys ? keys[index]: index;
           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){
          index0= keys ? keys[index] : index;
          memo= obj[index0];
          index += dir;
        }
        return iterator (obj, iteratee, memo, keys, index, length);
      }
    }
    _.reduce = _.foldl = _.inject = createReduce(1);
    _.reduceRight = _.foldr = createReduce(-1);


_.shuffle(把list随机排序)

    _.random= function(min, max){
      if(max === null){
        max= min;
        min= 0;
      }
      return min + Math.floor(Math.random*(max- min + 1));
    }
    _.values= function(obj){
      var keys= _.keys(obj);
          length= keys.length;
          values= Array(length);
      for(var i= 0; i< length; i++){
        values[i]= obj[keys[i]]
      }
      return values;
    }
    _.shuffle = function(obj){
      var set= isArrayLike(obj) ? obj : _.values(obj);
          length= set.length;
          shuffles= Array(length);
      for(var i= 0, rand; i< length; i++){
        rand= _.random(0, i);
        if (rand !== i){
          shuffles[index]=shuffles[rand];
        }
        shuffles[rand]=set[index];
      }
      return shuffles;
    }


_.sample(从list中随机去除样本)

    _.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(according the callBack function to sort the list) example:

var stooges = [{name: ‘moe’, age: 40}, {name: ‘larry’, age: 50}, {name: ‘curly’, age: 60}]; _.sortBy(stooges, ‘name’); => [{name: ‘curly’, age: 60}, {name: ‘larry’, age: 50}, {name: ‘moe’, age: 40}];

origin code:

    _.property= function(key){
      return function(obj){
        return obj === null ? void 0: obj[key];
      };
    };
    _.pluck= function(obj, key){
      return _.map(obj, _.property(key));
    }
    _.sortBy= function(obj, iteratee, context){
       var iteratee= cb(iteratee, context);
       return _.pluck(_.map(obj,function(value, index, list){
           return {
             value: value;
             index: index;
             result: iteratee(value, index, obj);
           }
         })
         .sort(function(left, right){
           var a= left.result;
               b= right.result;
           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')
    }


_.groupBy, _.indexBy, _.countBy
example:

    _.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
    => {1: [1.3], 2: [2.1, 2.4]}


sourceCode

    function group(behavior){
      return function(obj, iteratee, context){
        iteratee= cb(iteratee, context);
        var result= {};
        _.each(obj, function(value, index){
          var key= iteratee(value, index, obj);
          behavior(result, value, key);
        })
        return result;
      }
    }
    _.groupBy= group(function(result, key, value){
      return _.has(result, key)? result[key].push(value): result[key]= [value];
    });
    _.indexBy= group(function(result, key, value){
      return result[key]= value;
    })
    _.countBy= group(function(){
      return _.has(result, key)? result[key]++: result[key]= 1;
    });