Map is another important functional paradigm where you iterate over a object and perform some changes to the original objects.
The way underscore implements the map function is pretty simple.

  _.map = _.collect = function(obj, iterator, context) {
    var results = [];
    if (obj == null) return results;
    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    each(obj, function(value, index, list) {
      results.push(iterator.call(context, value, index, list));
    });
    return results;
  };

The map(aliased as collect) takes the object to interate over as a parameter and the iteration function as the parameter.

_.map = _.collect = function(obj, iterator, context) {

We create an empty array to store the computation per iteration.We do a simple null check and return the empty error if null.

  var results = [];
  if (obj == null) return results;

We then check if native map is present.If it is present we delegate the map job to the native implementation.
We then run our own iterator using the previously implemented each method and then store the values into the array defined before.Finally we return the array.

  each(obj, function(value, index, list) {
    results.push(iterator.call(context, value, index, list));
  });
  return results;



Functional programming is the paradigm of programming where the functions are passed as arguments to methods and operations are performed on the function.Underscore makes use of this in a very clean and generic way.

The goal for the each method is to iterate over array or object provided as arguments in the function call.

var each = _.each = _.forEach = function(obj, iterator, context) {
    if (obj == null) return obj;
    if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } else if (obj.length === +obj.length) {
      for (var i = 0, length = obj.length; i < length; i++) {
        if (iterator.call(context, obj[i], i, obj) === breaker) return;
      }
    } else {
      var keys = _.keys(obj);
      for (var i = 0, length = keys.length; i < length; i++) {
        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
      }
    }
    return obj;
  };

The object/array to be iterated is passed as the first argument.A basic null check is performed and the obj is returned ie null.

if (obj == null) return obj;

We then check if the ecmascript 5's native forEach is present, if it is present we use it instead of implementing our version for each.

if (nativeForEach && obj.forEach === nativeForEach) {
      obj.forEach(iterator, context);
    } 

Javascript has neat way to check to check if a variable is a number object

3===+3

Return true

The way it works is it passes the + message to the object and === does a equality and type check.

obj.length === +obj.length

Since obj.length is a number ,we perform a check if it a number.which in turn checks if obj is array.
We then loop over each of the items in the array and pass the value to the interator function and call it.

for (var i = 0, length = obj.length; i < length; i++) {
        if (iterator.call(context, obj[i], i, obj) === breaker) return;
      }

If obj is an object we get the keys of the objects using underscore's builtin _.keys method.

var keys = _.keys(obj);
      for (var i = 0, length = keys.length; i < length; i++) {
        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
      }

We call the iterator sending the values of the key in the object.



When every you include underscore into your code,it does a certain number of checks to make sure that there is no conflict and dependency issues.It also does a check and setup of the parameters that are required to use underscore.

  var root = this;
  var previousUnderscore = root._;
  var breaker = {};
  var ArrayProto = Array.prototype, ObjectProto = Object.prototype, FuncProto = Function.prototype;

  var 
    push = ArrayProto.push,
    slice = ArrayProto.slice,
    concat = ArrayProto.concat,
    toString = ObjectProto.toString,
    hasOwnProperty   = ObjProto.hasOwnProperty;

  var
    nativeForEach      = ArrayProto.forEach,
    nativeMap          = ArrayProto.map,
    nativeReduce       = ArrayProto.reduce,
    nativeReduceRight  = ArrayProto.reduceRight,
    nativeFilter       = ArrayProto.filter,
    nativeEvery        = ArrayProto.every,
    nativeSome         = ArrayProto.some,
    nativeIndexOf      = ArrayProto.indexOf,
    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    nativeIsArray      = Array.isArray,
    nativeKeys         = Object.keys,
    nativeBind         = FuncProto.bind;

  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

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

  _.VERSION = '1.5.2';
var root = this;

Underscore sets root as this ie it sets the root as the windows of the javascript context.

var previousUnderscore = root._;

We save the previous underscore in previousUnderscore.

var breaker = {};

Creates an empty object used later to break out out a loop.

var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;

Creates an empty Array object and function to work on later.

 var
    push             = ArrayProto.push,
    slice            = ArrayProto.slice,
    concat           = ArrayProto.concat,
    toString         = ObjProto.toString,
    hasOwnProperty   = ObjProto.hasOwnProperty;

Create references for the function so that we dont have to recreate one every time we have to use it.

var
    nativeForEach      = ArrayProto.forEach,
    nativeMap          = ArrayProto.map,
    nativeReduce       = ArrayProto.reduce,
    nativeReduceRight  = ArrayProto.reduceRight,
    nativeFilter       = ArrayProto.filter,
    nativeEvery        = ArrayProto.every,
    nativeSome         = ArrayProto.some,
    nativeIndexOf      = ArrayProto.indexOf,
    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    nativeIsArray      = Array.isArray,
    nativeKeys         = Object.keys,
    nativeBind         = FuncProto.bind;

Create references for the native Ecmascript 5 implementation.

var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  };

Create a variable _ function.if underscore is already loaded we return it.If _ is not the same as the one loaded.we return a new instance of underscore.

Required to use underscore with node.js.

_.VERSION = '1.5.2'

Sets the version of underscore.



Underscore is a set of utility functions written in underscore.With more than 80 different functions to make our lives easier.Its time to dissect them and understand how they work.

Underscore includes some setup code along with the functions below in the raw source of the library.The rest of the 80+ functions are mentioned below:

Underscore SetupĀ 

  1. Each method
  2. Map method
  3. Reduce method
  4. ReduceRight method
  5. Find method
  6. Filter method
  7. Reject method
  8. Every method
  9. Any method
  10. Contains method
  11. Invoke method
  12. Pluck method
  13. Where method
  14. FindWhere method
  15. Max method
  16. Min method
  17. Shuffle method
  18. Sample method
  19. SortBy method
  20. GroupBy method
  21. IndexBy method
  22. Countby method
  23. SortedIndex method
  24. ToArray method
  25. Size method
  26. First method
  27. Initial method
  28. Last method
  29. Rest method
  30. Compact method
  31. Flatten method
  32. Without method
  33. Uniq method
  34. Union method
  35. Intersection method
  36. Difference method
  37. Zip method
  38. Object method
  39. IndexOf method
  40. LastIndexOf method
  41. Range method
  42. Bind method
  43. Partial method
  44. BindAll method
  45. Memoize method
  46. Delay method
  47. Defer method
  48. Throttle method
  49. Debounce method
  50. Once method
  51. Wrap method
  52. Compose method
  53. After method
  54. Keys method
  55. Values method
  56. Pairs method
  57. Invert method
  58. Functions method
  59. Extend method
  60. Omit method
  61. Defaults method
  62. Clone method
  63. Tap method
  64. Isequal method
  65. isempty method
  66. isElement method
  67. isArray method
  68. isObject method
  69. isFinite method
  70. isNaN method
  71. isBoolean method
  72. isNull method
  73. isUndefined method
  74. has method
  75. isFinite method
  76. identity method
  77. times method
  78. random method
  79. result method
  80. mixin method
  81. template method
  82. chain method