node-deep-extend icon indicating copy to clipboard operation
node-deep-extend copied to clipboard

Add ability to supply custom cloing logic

Open watson opened this issue 10 years ago • 3 comments
trafficstars

Warning: This is a highly opinionated change so I understand if it doesn't fit the vision of this module. Also it should be released as a breaking change due to the new initializer function.

My use case is that I use deep-extend to clone MongoDB documents. They contain custom MongoDB types like Timestamp and ObjectId. This module will think they are regular object literals and extend them like any other object literal. This unfortunately means that they lose their relation to their original classes so you no longer can do an obj instanceof Klass.

This pull request adds new functionality which allows you to supply a custom cloning function which will be called for each value that deep-extend attempts to clone. If the cloning function returns a falsy value the regular behaviour of deep-extend is used, but if the cloning function returns any truthy value, that value will be used as the new value:

var Foo = function(val) {
  this.foo = val;
};
var Bar = function(val) {
  this.bar = val;
};

var cloner = function (obj) {
  // if given an instance of Foo, return a clone of it
  if (obj instanceof Foo) return new Foo(obj.foo);
};

var deepExtend = require('deep-extend')(cloner);
var obj = {
  a: new Foo(1),
  b: new Bar(2)
};

var clone = deepExtend({}, obj);

console.log(clone);
/*
{ a: { foo: 1 },
  b: { bar: 2 } }
*/
console.log(clone.a instanceof Foo); // true
console.log(clone.b instanceof Bar); // false

watson avatar Jan 14 '15 17:01 watson

@watson How about different interface? May be just add some methods to main function?

Something like this?:

var deepExtend = require('deep-extend');
var customExtend = deepExtend.customExtender(cloner);

var standardCloned = deepExtend({}, obj); // standard behavior
var customCloned = customExtend({}, obj); // with custom logic

It will save backward compatibility.

unclechu avatar Mar 28 '15 13:03 unclechu

That's not such a bad idea... you could also do it with a submodule like in is-my-json-valid:

var deepExtend = require('deep-extend');
var customExtend = require('deep-extend/custom')(cloner);

var standardCloned = deepExtend({}, obj); // standard behavior
var customCloned = customExtend({}, obj); // with custom logic

I kind of prefer the latter since adding a function to a custom property on the normal deepExtend function seems a little hack'ish. But I might be wrong.

I can update the pull request with which ever version you prefer?

watson avatar Mar 29 '15 01:03 watson

@watson Last version is better.

var deepExtend = require('deep-extend');
var customExtend = require('deep-extend/custom')(cloner);

unclechu avatar Mar 29 '15 18:03 unclechu