1

Expected results

I've written a function to take a simple object literal, and reformat it as seen in this example:

var original = { a: 1, b: true, c: "a string" }

// run through function ...

var result = { 
  a: { type: "int", val: 1 }, 
  b: { type: "bit", val: 1 }, 
  c: { type: "varchar(250)", val: "a string" }
}

Current Solution

The function works, using a for ... in loop to iterate over the original object & build a new object based on the original data.

function change (data) {

  function loop (d) {

    var orig = d;
    var end = d;

    for (var key in orig) {

      var property = {
        type: "test",
        val: orig[key]
      };

      end[key] = property;
    }

    return end;
  }

  // create object using loop & return
  var p = loop(data);
  return p;

}

Actual results

However, this function is also changing the original object passed in & I can't seem to figure out why.

var original = { a: 1, b: true, c: "a string" }

// run through function ...
var result = change(original);  

console.log(result);    // =>  { 
                        //        a: { type: "int", val: 1 }, 
                        //        b: { type: "bit", val: 1 }, 
                        //        c: { type: "varchar(250)", val: "a string" }
                        //      }

console.log(original);  // =>  { 
                        //        a: { type: "int", val: 1 }, 
                        //        b: { type: "bit", val: 1 }, 
                        //        c: { type: "varchar(250)", val: "a string" }
                        //      }
                        // instead of expected: 
                        //      { a:1, b:true, c:"a string" }

I'm guessing that it has something to do with my not fully understanding scope in javascript & possibly something about prototypical inheritance (which I definitely need to learn more about), but at this point I'm just not sure where to begin to really understand what's happening here. And I'm just extra confused when I compare it to my simple understanding of side-affecting in JavaScript:

var a = 1;
var b = a;
console.log(a) // => 1
console.log(b) // => 1

b = 2
console.log(a) // => 1
console.log(b) // => 2

The function works as is and is doing what I need it to in the rest of my program, but this issue is really bothering me since I don't understand what's going on here.

  • var newObject = oldObject does not create a copy of an oldObject – Jaromanda X Jul 27 '16 at 04:31
  • Possible duplicate of [Copy a variable's value into another](http://stackoverflow.com/questions/18829099/copy-a-variables-value-into-another) – Bálint Jul 27 '16 at 04:34
  • so, any change to properties of orig, end or d in the function will change original as well – Jaromanda X Jul 27 '16 at 04:37
  • 1
    simply defining `var end = {}` will fix your issue – Jaromanda X Jul 27 '16 at 04:38
  • @JaromandaX yes, that seems to be exactly what's happening. How do I avoid it? I'm guessing it's something really simple I'm overlooking, but I can't seem to figure it out... – Andrew Chang-DeWitt Jul 27 '16 at 04:39
  • This happens because objects are passed by sharing (a reference). You have to distinguish between mutation and reassignment. [Look into this answer](http://stackoverflow.com/a/38533677/6445533) –  Jul 27 '16 at 06:16

1 Answers1

1

In Javascript when an object is passed as an argument if you decide to mutate it in the function that will be a reference to the original object and will mutate it too.

If you just handle it like read only it would be just as a regular argument ( passed by value )

For Objects that are flat ( do not contain nested objects ) you can use Object.assign (Es6 feature with available polyfill)

let obj1 = { a: 1};
let obj2 = Object.assign({}, obj1);

For more complex objects i suggest you use some library method like lodash's _.cloneDeep

// you have to include lodash.js in your page
let obj1 = { a: 1};
let obj2 = _.cloneDeep(obj1);

or jQuery's $.extend

// you have to include jquery.js in your page
let obj1 = { a: 1};
let obj2 = $.extend(true, {}, obj1);
eltonkamami
  • 5,134
  • 1
  • 22
  • 30