167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var clone = (function() {
 | 
						|
'use strict';
 | 
						|
 | 
						|
/**
 | 
						|
 * Clones (copies) an Object using deep copying.
 | 
						|
 *
 | 
						|
 * This function supports circular references by default, but if you are certain
 | 
						|
 * there are no circular references in your object, you can save some CPU time
 | 
						|
 * by calling clone(obj, false).
 | 
						|
 *
 | 
						|
 * Caution: if `circular` is false and `parent` contains circular references,
 | 
						|
 * your program may enter an infinite loop and crash.
 | 
						|
 *
 | 
						|
 * @param `parent` - the object to be cloned
 | 
						|
 * @param `circular` - set to true if the object to be cloned may contain
 | 
						|
 *    circular references. (optional - true by default)
 | 
						|
 * @param `depth` - set to a number if the object is only to be cloned to
 | 
						|
 *    a particular depth. (optional - defaults to Infinity)
 | 
						|
 * @param `prototype` - sets the prototype to be used when cloning an object.
 | 
						|
 *    (optional - defaults to parent prototype).
 | 
						|
*/
 | 
						|
function clone(parent, circular, depth, prototype) {
 | 
						|
  var filter;
 | 
						|
  if (typeof circular === 'object') {
 | 
						|
    depth = circular.depth;
 | 
						|
    prototype = circular.prototype;
 | 
						|
    filter = circular.filter;
 | 
						|
    circular = circular.circular
 | 
						|
  }
 | 
						|
  // maintain two arrays for circular references, where corresponding parents
 | 
						|
  // and children have the same index
 | 
						|
  var allParents = [];
 | 
						|
  var allChildren = [];
 | 
						|
 | 
						|
  var useBuffer = typeof Buffer != 'undefined';
 | 
						|
 | 
						|
  if (typeof circular == 'undefined')
 | 
						|
    circular = true;
 | 
						|
 | 
						|
  if (typeof depth == 'undefined')
 | 
						|
    depth = Infinity;
 | 
						|
 | 
						|
  // recurse this function so we don't reset allParents and allChildren
 | 
						|
  function _clone(parent, depth) {
 | 
						|
    // cloning null always returns null
 | 
						|
    if (parent === null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    if (depth == 0)
 | 
						|
      return parent;
 | 
						|
 | 
						|
    var child;
 | 
						|
    var proto;
 | 
						|
    if (typeof parent != 'object') {
 | 
						|
      return parent;
 | 
						|
    }
 | 
						|
 | 
						|
    if (clone.__isArray(parent)) {
 | 
						|
      child = [];
 | 
						|
    } else if (clone.__isRegExp(parent)) {
 | 
						|
      child = new RegExp(parent.source, __getRegExpFlags(parent));
 | 
						|
      if (parent.lastIndex) child.lastIndex = parent.lastIndex;
 | 
						|
    } else if (clone.__isDate(parent)) {
 | 
						|
      child = new Date(parent.getTime());
 | 
						|
    } else if (useBuffer && Buffer.isBuffer(parent)) {
 | 
						|
      if (Buffer.allocUnsafe) {
 | 
						|
        // Node.js >= 4.5.0
 | 
						|
        child = Buffer.allocUnsafe(parent.length);
 | 
						|
      } else {
 | 
						|
        // Older Node.js versions
 | 
						|
        child = new Buffer(parent.length);
 | 
						|
      }
 | 
						|
      parent.copy(child);
 | 
						|
      return child;
 | 
						|
    } else {
 | 
						|
      if (typeof prototype == 'undefined') {
 | 
						|
        proto = Object.getPrototypeOf(parent);
 | 
						|
        child = Object.create(proto);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        child = Object.create(prototype);
 | 
						|
        proto = prototype;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (circular) {
 | 
						|
      var index = allParents.indexOf(parent);
 | 
						|
 | 
						|
      if (index != -1) {
 | 
						|
        return allChildren[index];
 | 
						|
      }
 | 
						|
      allParents.push(parent);
 | 
						|
      allChildren.push(child);
 | 
						|
    }
 | 
						|
 | 
						|
    for (var i in parent) {
 | 
						|
      var attrs;
 | 
						|
      if (proto) {
 | 
						|
        attrs = Object.getOwnPropertyDescriptor(proto, i);
 | 
						|
      }
 | 
						|
 | 
						|
      if (attrs && attrs.set == null) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      child[i] = _clone(parent[i], depth - 1);
 | 
						|
    }
 | 
						|
 | 
						|
    return child;
 | 
						|
  }
 | 
						|
 | 
						|
  return _clone(parent, depth);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Simple flat clone using prototype, accepts only objects, usefull for property
 | 
						|
 * override on FLAT configuration object (no nested props).
 | 
						|
 *
 | 
						|
 * USE WITH CAUTION! This may not behave as you wish if you do not know how this
 | 
						|
 * works.
 | 
						|
 */
 | 
						|
clone.clonePrototype = function clonePrototype(parent) {
 | 
						|
  if (parent === null)
 | 
						|
    return null;
 | 
						|
 | 
						|
  var c = function () {};
 | 
						|
  c.prototype = parent;
 | 
						|
  return new c();
 | 
						|
};
 | 
						|
 | 
						|
// private utility functions
 | 
						|
 | 
						|
function __objToStr(o) {
 | 
						|
  return Object.prototype.toString.call(o);
 | 
						|
};
 | 
						|
clone.__objToStr = __objToStr;
 | 
						|
 | 
						|
function __isDate(o) {
 | 
						|
  return typeof o === 'object' && __objToStr(o) === '[object Date]';
 | 
						|
};
 | 
						|
clone.__isDate = __isDate;
 | 
						|
 | 
						|
function __isArray(o) {
 | 
						|
  return typeof o === 'object' && __objToStr(o) === '[object Array]';
 | 
						|
};
 | 
						|
clone.__isArray = __isArray;
 | 
						|
 | 
						|
function __isRegExp(o) {
 | 
						|
  return typeof o === 'object' && __objToStr(o) === '[object RegExp]';
 | 
						|
};
 | 
						|
clone.__isRegExp = __isRegExp;
 | 
						|
 | 
						|
function __getRegExpFlags(re) {
 | 
						|
  var flags = '';
 | 
						|
  if (re.global) flags += 'g';
 | 
						|
  if (re.ignoreCase) flags += 'i';
 | 
						|
  if (re.multiline) flags += 'm';
 | 
						|
  return flags;
 | 
						|
};
 | 
						|
clone.__getRegExpFlags = __getRegExpFlags;
 | 
						|
 | 
						|
return clone;
 | 
						|
})();
 | 
						|
 | 
						|
if (typeof module === 'object' && module.exports) {
 | 
						|
  module.exports = clone;
 | 
						|
}
 |