0

Just getting back into doing a lot of Javascript and trying to understand Javascript objects better. I asked previous question earlier but this one is different. Can I disconnect a reference relationship that exists between objects?

For example:

var objA={};
objA.my_name='Joe';
var objB=objA;
objB.my_name="jake"; // objA.my_name="jake"
objB.something="this is something";
objA.last_name="Jackson";
console.log(objA.something);  // "this si something" can add to parent object at runtime
console.log(objB.last_name);  // "Jackson" can add to child object at runtime
// now I'd like to cut off objB from objA such that:
objB.cell_phone='323-213-2323';
console.log(objA.cell_phone); // '323-213-2323' but would like undefined; would like this behavior

thx in advance

timpone
  • 19,235
  • 36
  • 121
  • 211
  • 1
    You mean, how to clone an object? – John Dvorak Jan 21 '13 at 18:31
  • no, I'd like reference behavior at beginning but then be able to tell it to stop. I looked at the cloning answers but would like reference behavior at start and then disconnect – timpone Jan 21 '13 at 18:32
  • When you do this: `var objB = objA;` you end up with just one object; it's one object with two separate variables pointing at it. There's no "lazy clone" mechanism in JavaScript. – Pointy Jan 21 '13 at 18:34
  • @timpone so you mean, how to clone an object later on? Or, you want two objects that will temporarily mirror each other's state? – John Dvorak Jan 21 '13 at 18:36
  • the latter. basically create a reference relationship and then, at a later point, be able to disconnect the relationship. I think the answer below gets at it which is that we can't really do real metraprogramming in Javascript this way (maybe some other way) – timpone Jan 21 '13 at 18:39

1 Answers1

3

You can't tell an object to stop having reference behavior. That's the way javascript works.

You can copy an object so that you create a totally new object with the same properties as the original, but a completely separate object that won't have reference behavior.

A shallow copy can be made by simply iterating over the properties of an object and assigning each one to a new object.

function shallowCopy(src, dest) {
    for (var prop in src) {
        if (src.hasOwnProperty(prop)) {
            dest[prop] = src[prop];
        }
    }
} 

A shallow copy of an array can be done like this:

var arr = [1,2,3];
var copyArr = [].slice.call(arr, 0);

Deep copies where properties that are objects or arrays themselves are also copied requires more work because you essentially have to check if they are objects or arrays and then recursively copy them and their contents. Shallow copies, as shown here, are much easier and, if you know the contents of your data are often sufficient.


If you want to look at an advanced version of copying (including deep copying), you can see the code for jQuery's .extend() function here. Follow that link and search for fn.extend.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • It's not just "simply iterating over the properties", if properties themselves are objects or arrays of objects you need recursion. – Christophe Jan 21 '13 at 18:33
  • Too bad there's no easy and generic way to make a deep copy of any object. – John Dvorak Jan 21 '13 at 18:33
  • @Christophe - that's why that sentence says "shallow copy". – jfriend00 Jan 21 '13 at 18:34
  • 1
    Note that if `arr` is a real array, then `arr.slice(0)` will do as well. – John Dvorak Jan 21 '13 at 18:35
  • @JanDvorak the closest thing to a real deep copy is to use `var copy = JSON.parse(JSON.serialize(original));` but that's somewhat disturbing. It also can't deal with object structures that aren't proper trees. (Not to mention `Date` instances, functions, etc.) – Pointy Jan 21 '13 at 18:36
  • 1
    @JanDvorak - yeah, I'm in the habit of doing it this way so it works on the various pseudo-arrays that appear occasionally (such as collections returned from DOM calls or the `arguments` pseudo-array). – jfriend00 Jan 21 '13 at 18:36
  • @jfriend00 not just `NodeList`, the `jQuery` object is a pseudo-array as well. – John Dvorak Jan 21 '13 at 18:37
  • @jfriend00 ok, I understand. I thought the OP was trying to avoid references to any object, not just the top level one. – Christophe Jan 21 '13 at 18:38
  • so short answer, no way to basicallly say disconnect the reference relationship such that changes or additions to objB will not be propogated back through objA? – timpone Jan 21 '13 at 18:41
  • @timpone - yep, that's what the first sentence of my answer says. You have to explicitly make a copy if you want a copy. – jfriend00 Jan 21 '13 at 18:47