function clone(value, deep, guard, stack, thorough) {
    if (value == null) {
      return value;
    }
    if (guard) {
      deep = false;
    }
    // avoid slower checks on primitives
    thorough || (thorough = { 'value': null });
    if (thorough.value == null) {
      // primitives passed from iframes use the primary document's native prototypes
      thorough.value = !!(BoolProto.clone || NumberProto.clone || StringProto.clone);
    }
    // use custom `clone` method if available
    var isObj = objectTypes[typeof value];
    if ((isObj || thorough.value) && value.clone && isFunction(value.clone)) {
      thorough.value = null;
      return value.clone(deep);
    }
    // inspect [[Class]]
    if (isObj) {
      // don't clone `arguments` objects, functions, or non-object Objects
      var className = toString.call(value);
      if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) {
        return value;
      }
      var isArr = className == arrayClass;
      isObj = isArr || (className == objectClass ? isPlainObject(value, true) : isObj);
    }
    // shallow clone
    if (!isObj || !deep) {
      // don't clone functions
      return isObj
        ? (isArr ? slice.call(value) : extend({}, value))
        : value;
    }

    var ctor = value.constructor;
    switch (className) {
      case boolClass:
        return new ctor(value == true);

      case dateClass:
        return new ctor(+value);

      case numberClass:
      case stringClass:
        return new ctor(value);

      case regexpClass:
        return ctor(value.source, reFlags.exec(value));
    }

    // check for circular references and return corresponding clone
    stack || (stack = []);
    var length = stack.length;
    while (length--) {
      if (stack[length].source == value) {
        return stack[length].value;
      }
    }

    // init cloned object
    length = value.length;
    var result = isArr ? ctor(length) : {};

    // add current clone and original source value to the stack of traversed objects
    stack.push({ 'value': result, 'source': value });

    // recursively populate clone (susceptible to call stack limits)
    if (isArr) {
      var index = -1;
      while (++index < length) {
        result[index] = clone(value[index], deep, null, stack, thorough);
      }
    } else {
      forOwn(value, function(objValue, key) {
        result[key] = clone(objValue, deep, null, stack, thorough);
      });
    }
    return result;
  }
Creates a clone of `value`. If `deep` is `true`, all nested objects will
also be cloned otherwise they will be assigned by reference. If a value has
a `clone` method it will be used to perform the clone. Functions, DOM nodes,
`arguments` objects, and objects created by constructors other than `Object`
are **not** cloned unless they have a custom `clone` method.

@static
@memberOf _
@category Objects
@param {Mixed} value The value to clone.
@param {Boolean} deep A flag to indicate a deep clone.
@param {Object} [guard] Internally used to allow this method to work with
 others like `_.map` without using their callback `index` argument for `deep`.
@param {Array} [stack=[]] Internally used to keep track of traversed objects
 to avoid circular references.
@param {Object} thorough Internally used to indicate whether or not to perform
 a more thorough clone of non-object values.
@returns {Mixed} Returns the cloned `value`.
@example

var stooges = [
  { 'name': 'moe', 'age': 40 },
  { 'name': 'larry', 'age': 50 },
  { 'name': 'curly', 'age': 60 }
];

_.clone({ 'name': 'moe' });
// => { 'name': 'moe' }

var shallow = _.clone(stooges);
shallow[0] === stooges[0];
// => true

var deep = _.clone(stooges, true);
shallow[0] === stooges[0];
// => false