0

I have few JS objects. They can have any structure:

{
  name: "first",
  _ref_id: 1234,
  spec: {
    _ref_id: 2345,
    data: "lots of data"
  }
}

{
  name: 'second',
  _ref_id: 5678,
  container: {
    _ref_id: 6789,
    children: [
      {_ref_id: 3214, name: 'Bob'}
      {_ref_id: 1111, name: 'Mark'}
      {_ref_id: 2222, name: 'Frank'}
    ]
  }
}

Problem:

I need to make a copies of this object but with a different _ref_ids.

Creation of the 'first' object my look like this:

first = {
  name: "first",
  _ref_id: uuid.v4(),
  spec: {
    _ref_id: uuid.v4(),
    data: "lots of data"
  }
}

So I know the structure of the object when I am creating it but further down the chain in a place where I am trying to make a copy of this object I don't have access and I don't know what is the structure of this object all I have is the object it self. So after coping 'first' I would like to have:

{
  name: "first",
  _ref_id: 8888,
  spec: {
    _ref_id: 9999,
    data: "lots of data"
  }
} 

I tried instead of defining the _ref_id a simple value a sort of memoized function during the object creation:

refId(memoized = true){
  var memo = {}
  return () => {
    if(!memoized) memo = {}
    if(memo['_ref_id'])
      return memo._ref_id
    else {
      memo._ref_id = uuid.v4()
      return memo._ref_id
    }
  }
}

So I can create it:

first = {
  name: "first",
  _ref_id: refId(),
  spec: {
    _ref_id: refId(),
    data: "lots of data"
  }
}

And change the first._ref_id to first._ref_id() whenever I am trying to access the value of it.

But I have no idea how to reset the memoized variable from inside the coping function or if this is even possible?

Have anyone had similar problem? Maybe there is a different way to solve it?

PS:

I am using lodash and immutable.js in this project but I haven't found any helper functions for this particular task.

Kocur4d
  • 6,701
  • 8
  • 35
  • 53
  • I'm not familiar with memoization but I don't see how it helps solving your problem. I would go for a deep copy approach during which I would look out for the "transient field" to reinstantiate it rather than copying it. – Aaron Feb 05 '16 at 14:46
  • memoization is just for when I am **first._ref_id()** the same object all over again i will always get the same result. But if somehow I will 'inject'/change the value of memoized variable in between the calls the new value will be generated. But my way of thinking could be totally wrong. Can you provide the example with your solution? – Kocur4d Feb 05 '16 at 14:50
  • 1
    variables held in closures (as in your memoizer) are one of the worst things for object copying. Only the original function has access to it, and there's no way to make a "new" copy of that variable. – Alnitak Feb 05 '16 at 15:04
  • @Alnitak yes thats what I thought - Aaron solution works perfectly fine but I am still wondering if it is possible to build something with my initial approach - using closures/currying to make this work. Do you have any ideas? – Kocur4d Feb 05 '16 at 15:33

1 Answers1

1

Inspired from Most elegant way to clone a JS object, with a check for _ref_id fields :

function deepCopyWithNewRefId(obj) {
    if (null == obj || "object" != typeof obj) return obj;
        var copy = obj.constructor();
        for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) {
            if (attr == "_ref_id") {
                copy[attr] = uuid.v4();
            } else {
                copy[attr] = deepCopyWithNewRefId(obj[attr]);
            }
        }
    }
    return copy;
}

A log of its use :

var uuid = { v4 : function(){ return Math.random()} };
var first = {
  name: "first",
  _ref_id: uuid.v4(),
  spec: {
    _ref_id: uuid.v4(),
    data: "lots of data"
  }
};
console.log(first._ref_id);
console.log(first.spec._ref_id);
var second = deepCopyWithNewRefId(first);
console.log(second);
console.log(second._ref_id);
console.log(second.spec._ref_id);
// the printed values are not the same. The rest of the object is
Community
  • 1
  • 1
Aaron
  • 24,009
  • 2
  • 33
  • 57
  • Cool that worked perfectly fine for all examples I run. I will wait few days with accepting it as an answer, I am just very interested to see if it could be done with a different approach. I will do a bit more research over the weekend. Thank you very much mate. – Kocur4d Feb 05 '16 at 15:30
  • You're welcome ! There's at least another method for deep-copying object in JS through the use of JSON.parse / JSON.stringify, where JSON.parse conveniently accepts a callback method that would grant it the possibility to change your _ref_id field value. The code would be much more concise but I've read it's also much less efficient. – Aaron Feb 05 '16 at 15:34
  • @Aaron IMHO, using serialising to copy objects is horrible. I've seen it used on HTML too, it's just not right! – Alnitak Feb 05 '16 at 15:35
  • 1
    @Alnitak It makes me think about people emailing a photo of their screen because they don't know about printscreen :-/ – Aaron Feb 05 '16 at 15:36