src/index.js
function _clone (opts, source, target) {
  let type = toType(source)
  switch (type) {
    case 'String':
    case 'Number':
    case 'Boolean':
    case 'Null':
    case 'Undefined':
    case 'Symbol':
    case 'DOMPrototype': // (browser)
    case 'process': // (node) cloning this is not a good idea
      target = source
      break
    case 'Function':
      if (!target) {
        let _bind = (opts.bind === null ? null : opts.bind || source)
        if (opts.wrapFn) {
          target = function () {
            return source.apply(_bind, arguments)
          }
        } else {
          target = source.bind(_bind)
        }
      }
      target = _props(opts, source, target)
      break
    case 'Int8Array':
    case 'Uint8Array':
    case 'Uint8ClampedArray':
    case 'Int16Array':
    case 'Uint16Array':
    case 'Int32Array':
    case 'Uint32Array':
    case 'Float32Array':
    case 'Float64Array':
      target = new source.constructor(source)
      break
    case 'Array':
      target = source.map(function (item) {
        return _clone(opts, item)
      })
      target = _props(opts, source, target)
      break
    case 'Date':
      target = new Date(source)
      break
    case 'Error':
    case 'EvalError':
    case 'InternalError':
    case 'RangeError':
    case 'ReferenceError':
    case 'SyntaxError':
    case 'TypeError':
    case 'URIError':
      target = new source.constructor(source.message)
      target = _props(opts, source, target)
      target.stack = source.stack
      break
    case 'RegExp':
      let flags = source.flags ||
        (source.global ? 'g' : '') +
        (source.ignoreCase ? 'i' : '') +
        (source.multiline ? 'm' : '')
      target = new RegExp(source.source, flags)
      break
    case 'Buffer':
      target = new source.constructor(source)
      break
    case 'Window': // clone of global object
    case 'global':
      opts.wrapFn = true
      target = _props(opts, source, target || {})
      break
    case 'Math':
    case 'JSON':
    case 'Console':
    case 'Navigator':
    case 'Screen':
    case 'Object':
      target = _props(opts, source, target || {})
      break
    default:
      if (/^HTML/.test(type)) { // handle HTMLElements
        if (source.cloneNode) {
          target = source.cloneNode(true)
        } else {
          target = source
        }
      } else if (typeof source === 'object') { // handle other object based types
        target = _props(opts, source, target || {})
      } else { // anything else should be a primitive
        target = source
      }
  }
  return target
}
function _clone (opts, source, target) {
  let type = toType(source)
  switch (type) {
    case 'String':
    case 'Number':
    case 'Boolean':
    case 'Null':
    case 'Undefined':
    case 'Symbol':
    case 'DOMPrototype': // (browser)
    case 'process': // (node) cloning this is not a good idea
      target = source
      break
    case 'Function':
      if (!target) {
        let _bind = (opts.bind === null ? null : opts.bind || source)
        if (opts.wrapFn) {
          target = function () {
            return source.apply(_bind, arguments)
          }
        } else {
          target = source.bind(_bind)
        }
      }
      target = _props(opts, source, target)
      break
    case 'Int8Array':
    case 'Uint8Array':
    case 'Uint8ClampedArray':
    case 'Int16Array':
    case 'Uint16Array':
    case 'Int32Array':
    case 'Uint32Array':
    case 'Float32Array':
    case 'Float64Array':
      target = new source.constructor(source)
      break
    case 'Array':
      target = source.map(function (item) {
        return _clone(opts, item)
      })
      target = _props(opts, source, target)
      break
    case 'Date':
      target = new Date(source)
      break
    case 'Error':
    case 'EvalError':
    case 'InternalError':
    case 'RangeError':
    case 'ReferenceError':
    case 'SyntaxError':
    case 'TypeError':
    case 'URIError':
      target = new source.constructor(source.message)
      target = _props(opts, source, target)
      target.stack = source.stack
      break
    case 'RegExp':
      let flags = source.flags ||
        (source.global ? 'g' : '') +
        (source.ignoreCase ? 'i' : '') +
        (source.multiline ? 'm' : '')
      target = new RegExp(source.source, flags)
      break
    case 'Buffer':
      target = new source.constructor(source)
      break
    case 'Window': // clone of global object
    case 'global':
      opts.wrapFn = true
      target = _props(opts, source, target || {})
      break
    case 'Math':
    case 'JSON':
    case 'Console':
    case 'Navigator':
    case 'Screen':
    case 'Object':
      target = _props(opts, source, target || {})
      break
    default:
      if (/^HTML/.test(type)) { // handle HTMLElements
        if (source.cloneNode) {
          target = source.cloneNode(true)
        } else {
          target = source
        }
      } else if (typeof source === 'object') { // handle other object based types
        target = _props(opts, source, target || {})
      } else { // anything else should be a primitive
        target = source
      }
  }
  return target
}
function _clone ( opts , source , target ) { let type = toType ( source ) switch ( type ) { case 'String' : case 'Number' : case 'Boolean' : case 'Null' : case 'Undefined' : case 'Symbol' : case 'DOMPrototype' : // (browser) case 'process' : // (node) cloning this is not a good idea target = source break case 'Function' : if ( ! target ) { let _bind = ( opts . bind === null ? null : opts . bind || source ) if ( opts . wrapFn ) { target = function ( ) { return source . apply ( _bind , arguments ) } } else { target = source . bind ( _bind ) } } target = _props ( opts , source , target ) break case 'Int8Array' : case 'Uint8Array' : case 'Uint8ClampedArray' : case 'Int16Array' : case 'Uint16Array' : case 'Int32Array' : case 'Uint32Array' : case 'Float32Array' : case 'Float64Array' : target = new source . constructor ( source ) break case 'Array' : target = source . map ( function ( item ) { return _clone ( opts , item ) } ) target = _props ( opts , source , target ) break case 'Date' : target = new Date ( source ) break case 'Error' : case 'EvalError' : case 'InternalError' : case 'RangeError' : case 'ReferenceError' : case 'SyntaxError' : case 'TypeError' : case 'URIError' : target = new source . constructor ( source . message ) target = _props ( opts , source , target ) target . stack = source . stack break case 'RegExp' : let flags = source . flags || ( source . global ? 'g' : '' ) + ( source . ignoreCase ? 'i' : '' ) + ( source . multiline ? 'm' : '' ) target = new RegExp ( source . source , flags ) break case 'Buffer' : target = new source . constructor ( source ) break case 'Window' : // clone of global object case 'global' : opts . wrapFn = true target = _props ( opts , source , target || { } ) break case 'Math' : case 'JSON' : case 'Console' : case 'Navigator' : case 'Screen' : case 'Object' : target = _props ( opts , source , target || { } ) break default : if ( / ^HTML / . test ( type ) ) { // handle HTMLElements if ( source . cloneNode ) { target = source . cloneNode ( true ) } else { target = source } } else if ( typeof source === 'object' ) { // handle other object based types target = _props ( opts , source , target || { } ) } else { // anything else should be a primitive target = source } } return target }
Recursively clone source

@static
@private
@param {Object} opts - options
@param {Object} [opts.bind] - optional bind for function clones
@param {Array} opts.visited - visited references to detect circularities
@param {Array} opts.cloned - visited references of clones to assign circularities
@param {Any} source - The object to clone
@return {Any} deep clone of `source`
Recursively clone source