Skip to content

Instantly share code, notes, and snippets.

@brittanmcg
Created October 7, 2015 22:13
Show Gist options
  • Save brittanmcg/f26134cb49d6cf73735c to your computer and use it in GitHub Desktop.
Save brittanmcg/f26134cb49d6cf73735c to your computer and use it in GitHub Desktop.
object with some values as objects
var obj = {
name: "Simon",
age: "20",
clothing: {
style: "simple",
isDouche: false
}
}
@paopay
Copy link

paopay commented Oct 7, 2015

if you're updating all attributes, you can just pass in a new object.

newObjAttrs = {
  name: "Bob",
  age: "21",
  clothing: {
    style: "douchy",
    isDouche: true
  }
};

function foo(obj, newObjAttrs) {
  var keys = Object.keys(obj);

  for(var i=0; i<keys.length; i++) {
    obj[keys[i]] = newObjAttrs[keys[i]];
  }

  return obj;
};

@arcin
Copy link

arcin commented Oct 8, 2015

If you want a deep copy, heres a recursive way.

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        isDouche: false
    }
}
function deepCopy (oldObj, newObj) {
  newObj = newObj || {};
  for (var key in oldObj) {
    if (typeof obj[key] === 'object') {
      newObj[key] = {};
      thing(obj[key], newObj[key]);
    }
    newObj[key] = obj[key];
    }
  }
  return newObj;
}

@georgebonnr
Copy link

Depends on what attributes need to change, and how often.

ES6 examples:

const newObj = Object.assign({}, obj, {clothing:{style:"complex"}})
const newObj = {
  ...obj,
  ...{
    age: "21"
  }
}

also check out https://lodash.com/docs#merge

@elreimundo
Copy link

Just to clean up @arcin 's suggestion, which is good but which has three errors (assigning newObj without checking its type first, iterating over the prototype without checking hasOwnProperty, and calling an incorrect method thing instead of deepCopy)

function deepCopy (oldObj, newObj) {
    if (_isObject(oldObj)) {
        if ( !_isObject(newObj) ) newObj = {};
        _each(oldObj, function(key, attribute) {
            newObj[key] = deepCopy(attribute, newObj[key]);
        });
    } else {
        newObj = oldObj;
    }
    return newObj;
}

function _isObject(target) {
    return typeof target === 'object'  && target; // since typeof null === 'object'
}

function _has(object, key) {
    return object.hasOwnProperty(key);
}

function _each(object, callback) {
    for (var key in object) {
        if ( !_has(object, key) ) continue;
        callback(key, object[key]);
    }
}

results in the console:

var old = { foo: 'bar', baz: { qux: 'nested' } };
< undefined
var newObj = { name: 'test' };
< undefined
var result = deepCopy(old, newObj);
< undefined
result
< Object {name: "test", foo: "bar", baz: Object {qux: "nested"} }
result === newObj
< true

note that all of these naive implementations (including mine) will "fail" if you have any circular references, e.g.

var ouroboros = {};
ouroboros.self = ouroboros;

since you will kick off an infinite loop. These deep copies work only for acyclic graphs or trees.

result in console:

> var ouroboros = {};
< undefined
> ouroboros.self = ouroboros;
< Object {self: Object}
> var result = deepCopy(ouroboros);
< Uncaught RangeError: Maximum call stack size exceeded(…)

@arcin
Copy link

arcin commented Oct 8, 2015

@elreimundo Thanks for clearing up those issues! I totally forgot to change thing to deepCopy when I renamed the function haha. @konamax123 Copying in JS is rough because there are a lot of subtleties to consider when duplicating the memory allocated to objects and their contents. If you want a solution free of headaches (for the most part) consider Immutable data structures. They use structural sharing so creating "copies" isn't really that expensive. A good library is Facebooks ImmutableJS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment