UNPKG

3.98 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 var proto;
76 if (typeof parent != 'object') {
77 return parent;
78 }
79
80 if (util.isArray(parent)) {
81 child = [];
82 } else if (util.isRegExp(parent)) {
83 child = new RegExp(parent.source, util.getRegExpFlags(parent));
84 if (parent.lastIndex) child.lastIndex = parent.lastIndex;
85 } else if (util.isDate(parent)) {
86 child = new Date(parent.getTime());
87 } else if (useBuffer && Buffer.isBuffer(parent)) {
88 child = new Buffer(parent.length);
89 parent.copy(child);
90 return child;
91 } else {
92 if (typeof prototype == 'undefined') {
93 proto = Object.getPrototypeOf(parent);
94 child = Object.create(proto);
95 }
96 else {
97 child = Object.create(prototype);
98 proto = prototype;
99 }
100 }
101
102 if (circular) {
103 var index = allParents.indexOf(parent);
104
105 if (index != -1) {
106 return allChildren[index];
107 }
108 allParents.push(parent);
109 allChildren.push(child);
110 }
111
112 for (var i in parent) {
113 var attrs;
114 if (proto) {
115 attrs = Object.getOwnPropertyDescriptor(proto, i);
116 }
117
118 if (attrs && attrs.set == null) {
119 continue;
120 }
121 child[i] = _clone(parent[i], depth - 1);
122 }
123
124 return child;
125 }
126
127 return _clone(parent, depth);
128}
129
130/**
131 * Simple flat clone using prototype, accepts only objects, usefull for property
132 * override on FLAT configuration object (no nested props).
133 *
134 * USE WITH CAUTION! This may not behave as you wish if you do not know how this
135 * works.
136 */
137clone.clonePrototype = function(parent) {
138 if (parent === null)
139 return null;
140
141 var c = function () {};
142 c.prototype = parent;
143 return new c();
144};