UNPKG

3.68 kBJavaScriptView Raw
1'use strict';
2
3function objectToString(o) {
4 return Object.prototype.toString.call(o);
5}
6
7// shim for Node's 'util' package
8// DO NOT REMOVE THIS! It is required for compatibility with EnderJS (http://enderjs.com/).
9var util = {
10 isArray: function (ar) {
11 return Array.isArray(ar) || (typeof ar === 'object' && objectToString(ar) === '[object Array]');
12 },
13 isDate: function (d) {
14 return typeof d === 'object' && objectToString(d) === '[object Date]';
15 },
16 isRegExp: function (re) {
17 return typeof re === 'object' && objectToString(re) === '[object RegExp]';
18 },
19 getRegExpFlags: function (re) {
20 var flags = '';
21 re.global && (flags += 'g');
22 re.ignoreCase && (flags += 'i');
23 re.multiline && (flags += 'm');
24 return flags;
25 }
26};
27
28
29if (typeof module === 'object')
30 module.exports = clone;
31
32/**
33 * Clones (copies) an Object using deep copying.
34 *
35 * This function supports circular references by default, but if you are certain
36 * there are no circular references in your object, you can save some CPU time
37 * by calling clone(obj, false).
38 *
39 * Caution: if `circular` is false and `parent` contains circular references,
40 * your program may enter an infinite loop and crash.
41 *
42 * @param `parent` - the object to be cloned
43 * @param `circular` - set to true if the object to be cloned may contain
44 * circular references. (optional - true by default)
45 * @param `depth` - set to a number if the object is only to be cloned to
46 * a particular depth. (optional - defaults to Infinity)
47 * @param `prototype` - sets the prototype to be used when cloning an object.
48 * (optional - defaults to parent prototype).
49*/
50
51function clone(parent, circular, depth, prototype) {
52 // maintain two arrays for circular references, where corresponding parents
53 // and children have the same index
54 var allParents = [];
55 var allChildren = [];
56
57 var useBuffer = typeof Buffer != 'undefined';
58
59 if (typeof circular == 'undefined')
60 circular = true;
61
62 if (typeof depth == 'undefined')
63 depth = Infinity;
64
65 // recurse this function so we don't reset allParents and allChildren
66 function _clone(parent, depth) {
67 // cloning null always returns null
68 if (parent === null)
69 return null;
70
71 if (depth == 0)
72 return parent;
73
74 var child;
75 if (typeof parent != 'object') {
76 return parent;
77 }
78
79 if (util.isArray(parent)) {
80 child = [];
81 } else if (util.isRegExp(parent)) {
82 child = new RegExp(parent.source, util.getRegExpFlags(parent));
83 if (parent.lastIndex) child.lastIndex = parent.lastIndex;
84 } else if (util.isDate(parent)) {
85 child = new Date(parent.getTime());
86 } else if (useBuffer && Buffer.isBuffer(parent)) {
87 child = new Buffer(parent.length);
88 parent.copy(child);
89 } else {
90 if (typeof prototype == 'undefined') child = Object.create(Object.getPrototypeOf(parent));
91 else child = Object.create(prototype);
92 }
93
94 if (circular) {
95 var index = allParents.indexOf(parent);
96
97 if (index != -1) {
98 return allChildren[index];
99 }
100 allParents.push(parent);
101 allChildren.push(child);
102 }
103
104 for (var i in parent) {
105 child[i] = _clone(parent[i], depth - 1);
106 }
107
108 return child;
109 }
110
111 return _clone(parent, depth);
112}
113
114/**
115 * Simple flat clone using prototype, accepts only objects, usefull for property
116 * override on FLAT configuration object (no nested props).
117 *
118 * USE WITH CAUTION! This may not behave as you wish if you do not know how this
119 * works.
120 */
121clone.clonePrototype = function(parent) {
122 if (parent === null)
123 return null;
124
125 var c = function () {};
126 c.prototype = parent;
127 return new c();
128};