3

This is from the beginning of the annotated source of _.js. Try though I may, my JavaScript abilities are not at a high enough level to understand what's going on here. I'm hoping someone can give a real step by step explanation. I really have literally no idea what the code below does besides somehow setting up the _ for use, despite that I understand each individual expression.

 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._ = _;
  }
temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
  • My Question, why does it matter what it does? – Shawn31313 Jul 15 '13 at 18:14
  • 4
    ....trying to learn and understand advanced coding techniques? – temporary_user_name Jul 15 '13 at 18:14
  • Okay, fair enough. Well first off, you need to know what `instanceof` does. The `instanceof` operator tests whether an object has in its prototype chain the prototype property of a constructor. More about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof – Shawn31313 Jul 15 '13 at 18:19
  • 1
    Patterns that check context before exposing are called [universal module definitions](https://github.com/umdjs/umd). [See here too.](http://stackoverflow.com/a/9009810/770127) – ryanve Jul 15 '13 at 18:34

2 Answers2

9
var _ = function(obj) {
    // Either serve as the identity function on `_` instances,
    // ... or instantiate a new `_` object for other input.

    // If an `_` instance was passed, return it.
    if (obj instanceof _) return obj;
    // If someone called `_(...)`, rather than `new _(...)`,
    // ... return `new _(...)` to instantiate an instance.
    if (!(this instanceof _)) return new _(obj);

    // If we are instantiating a new `_` object with an underlying,
    // ... object, set that object to the `_wrapped` property.
    this._wrapped = obj;
};

// If there is an exports value (for modularity)...
if (typeof exports !== 'undefined') {
    // If we're in Node.js with module.exports...
    if (typeof module !== 'undefined' && module.exports) {
        // Set the export to `_`
        exports = module.exports = _;
    }
    // Export `_` as `_`
    exports._ = _;
} else {
    // Otherwise, set `_` on the global object, as set at the beginning
    // ... via `(function(){ var root = this; /* ... */ }())`
    root._ = _;
}
matt3141
  • 4,303
  • 1
  • 19
  • 24
3

Well, the lower snippet is quite unrelated. Basically it's exporting the _ from the closure to the global scope, or using a module definition system if available. No great deal, and nothing to care about if you don't use modules.

The _ function shouldn't be that hard to understand. You need to know

So what it does:

  1. If the argument is an Underscore instance, return it unchanged.
  2. If the function is not called as a constructor (when the this context is not an Underscore instance) then do so and return that
  3. Else wrap the argument in the current instance
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375