Skip to content

Commit 3f0710c

Browse files
committed
Add ability to supply custom cloing logic
1 parent e376f84 commit 3f0710c

File tree

2 files changed

+98
-46
lines changed

2 files changed

+98
-46
lines changed

README.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Install
1414
Usage
1515
-----
1616

17-
var deepExtend = require('deep-extend');
17+
var deepExtend = require('deep-extend')();
1818
var obj1 = {
1919
a: 1,
2020
b: 2,
@@ -56,3 +56,44 @@ Usage
5656
e: { one: 1, two: 2 },
5757
h: /abc/g }
5858
*/
59+
60+
Custom Clone Logic
61+
------------------
62+
63+
The deep-extend module will by default extend all types of objects. But
64+
if you clone a custom object it will no longer be an instance of its
65+
original class. If this is important to you, you can supply a custom cloning
66+
function which you can use to implement your own cloning logic.
67+
68+
It will be called for every value in the object. If you return a falsy
69+
value the default behavior of deep-extend will be used. If you return a
70+
truthy value that value will be used as a replacement for the original
71+
value.
72+
73+
var Foo = function(val) {
74+
this.foo = val;
75+
};
76+
var Bar = function(val) {
77+
this.bar = val;
78+
};
79+
80+
var cloner = function (obj) {
81+
// if given an instance of Foo, return a clone of it
82+
if (obj instanceof Foo) return new Foo(obj.foo);
83+
};
84+
85+
var deepExtend = require('deep-extend')(cloner);
86+
var obj = {
87+
a: new Foo(1),
88+
b: new Bar(2)
89+
};
90+
91+
var clone = deepExtend({}, obj);
92+
93+
console.log(clone);
94+
/*
95+
{ a: { foo: 1 },
96+
b: { bar: 2 } }
97+
*/
98+
console.log(clone.a instanceof Foo); // true
99+
console.log(clone.b instanceof Bar); // false

index.js

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,62 +32,73 @@
3232
* If you wish to clone object, simply use that:
3333
* deepExtend({}, yourObj_1, [yourObj_N]) - first arg is new empty object
3434
*/
35-
var deepExtend = module.exports = function (/*obj_1, [obj_2], [obj_N]*/) {
36-
if (arguments.length < 1 || typeof arguments[0] !== 'object') {
37-
return false;
38-
}
3935

40-
if (arguments.length < 2) return arguments[0];
36+
var noop = function () {};
4137

42-
var target = arguments[0];
38+
module.exports = function (cloner) {
39+
if (!cloner) cloner = noop;
4340

44-
// convert arguments to array and cut off target object
45-
var args = Array.prototype.slice.call(arguments, 1);
41+
return function deepExtend(/*obj_1, [obj_2], [obj_N]*/) {
42+
if (arguments.length < 1 || typeof arguments[0] !== 'object') {
43+
return false;
44+
}
4645

47-
var key, val, src, clone, tmpBuf;
46+
if (arguments.length < 2) return arguments[0];
4847

49-
args.forEach(function (obj) {
50-
if (typeof obj !== 'object') return;
48+
var target = arguments[0];
5149

52-
for (key in obj) {
53-
if ( ! (key in obj)) continue;
50+
// convert arguments to array and cut off target object
51+
var args = Array.prototype.slice.call(arguments, 1);
5452

55-
src = target[key];
56-
val = obj[key];
53+
var key, val, src, clone, tmpBuf, custom;
5754

58-
if (val === target) continue;
55+
args.forEach(function (obj) {
56+
if (typeof obj !== 'object') return;
5957

60-
if (typeof val !== 'object' || val === null) {
61-
target[key] = val;
62-
continue;
63-
} else if (val instanceof Buffer) {
64-
tmpBuf = new Buffer(val.length);
65-
val.copy(tmpBuf);
66-
target[key] = tmpBuf;
67-
continue;
68-
} else if (val instanceof Date) {
69-
target[key] = new Date(val.getTime());
70-
continue;
71-
} else if (val instanceof RegExp) {
72-
target[key] = new RegExp(val);
73-
continue;
74-
}
58+
for (key in obj) {
59+
if ( ! (key in obj)) continue;
7560

76-
if (typeof src !== 'object' || src === null) {
77-
clone = (Array.isArray(val)) ? [] : {};
78-
target[key] = deepExtend(clone, val);
79-
continue;
80-
}
61+
src = target[key];
62+
val = obj[key];
63+
64+
if (val === target) continue;
8165

82-
if (Array.isArray(val)) {
83-
clone = (Array.isArray(src)) ? src : [];
84-
} else {
85-
clone = (!Array.isArray(src)) ? src : {};
66+
if (custom = cloner(val)) {
67+
target[key] = custom;
68+
continue;
69+
} else if (typeof val !== 'object' || val === null) {
70+
target[key] = val;
71+
continue;
72+
} else if (val instanceof Buffer) {
73+
tmpBuf = new Buffer(val.length);
74+
val.copy(tmpBuf);
75+
target[key] = tmpBuf;
76+
continue;
77+
} else if (val instanceof Date) {
78+
target[key] = new Date(val.getTime());
79+
continue;
80+
} else if (val instanceof RegExp) {
81+
target[key] = new RegExp(val);
82+
continue;
83+
}
84+
85+
if (typeof src !== 'object' || src === null) {
86+
clone = (Array.isArray(val)) ? [] : {};
87+
target[key] = deepExtend(clone, val);
88+
continue;
89+
}
90+
91+
if (Array.isArray(val)) {
92+
clone = (Array.isArray(src)) ? src : [];
93+
} else {
94+
clone = (!Array.isArray(src)) ? src : {};
95+
}
96+
97+
target[key] = deepExtend(clone, val);
8698
}
99+
});
87100

88-
target[key] = deepExtend(clone, val);
89-
}
90-
});
101+
return target;
102+
}
103+
};
91104

92-
return target;
93-
}

0 commit comments

Comments
 (0)