1

I need a simple function to map a list of primitive properties from one object to another. I wrote one myself, but I guess there's already a proven method to achieve this.

var mapProperties = function (props, from) {
    var to = {};

    for (var i = 0; i < props.length; i++) {
        to[props[i]] = from[props[i]];
    }

    return to;
}

Then use the function like:

var fromObj = {
   foo: "foo",
   bar: 1
}

var toObj = mapProperties(['foo', 'bar'], fromObj);

Any better ideas?

Yulian
  • 6,262
  • 10
  • 65
  • 92
  • 1
    There's no built in way to [**clone a javascript object**](https://stackoverflow.com/questions/728360/how-do-i-correctly-clone-a-javascript-object), what you have is probably fine if it works for you. – adeneo Jun 28 '17 at 14:54
  • What do you think is wrong with your code? Consider asking the question on [Code Review](https://codereview.stackexchange.com/). – PeterMader Jun 28 '17 at 14:55
  • @adeneo [I beg to differ](https://stackoverflow.com/a/10916838/1541563). It's a hack, but it _is_ built in, to be fair. – Patrick Roberts Jun 28 '17 at 15:28

3 Answers3

1

If you are not looking to DeepClone, Then you can use Object.assign to copy the values of all enumerable own properties from one or more source objects to a target object.

var fromObj = {
   foo: "foo",
   bar: 1
}

var targetObject = Object.assign({}, fromObj);
console.log(targetObject);

For Deep Cloning, you can use the JSON.parse and JSON.stringify methods.

var fromObj = {
   foo: "foo",
   bar: 1,
   deepClone : { 
      newProp : 2
   }
}

var targetObject =  JSON.parse(JSON.stringify(fromObj));
targetObject.deepClone.newProp = 4;
console.log(targetObject);
Abhinav Galodha
  • 9,293
  • 2
  • 31
  • 41
  • A more efficient deep cloning algorithm that also clones objects with cyclical references uses the history API hack: https://stackoverflow.com/a/10916838/1541563 – Patrick Roberts Jun 28 '17 at 15:19
0

There are a couple ways to clone. If all you need is a shallow clone (your object only contains one level of primitives), Object.assign() is a handy way to do it:

const fromObj = { a: 1, b: 2, c: 3 };
const toObj = Object.assign({}, fromObj);

The Object.assign() function basically says "Assign all properties from the other objects to the first one". By making the first one an empty object, it is effectively a clone.

If you need a more controlled copy, you can use Object.keys() so you don't have manually have an array that lists properties:

// concise example using reduce and assign
const cloneA = obj => Object.keys(obj).reduce((result, key) => Object.assign(result, { [key]: obj[key] }), {});

// using a for-loop
const cloneB = obj => {
  const result = {};
  const keys = Object.keys(obj);
  
  for(let i in keys) {
    result[keys[i]] = obj[keys[i]];
  }
  
  return result;
}

const fromObj = { a: 1, b: 2, c: 3 };
console.log(cloneA(fromObj));
console.log(cloneB(fromObj));

If you need to deal with anything other then primitives, you want a deep clone function. There are lots of libraries with them out there, so I won't re-implement one here, but basically it's a recursive version of one of my clone functions that checks if it's a primitive or not before the copy.

samanime
  • 25,408
  • 15
  • 90
  • 139
0

Here's an implementation that only copies primitives, following the convention of Object.assign():

function filterPrimitives (key) {
  return !(this[key] instanceof Object)  
}

function clonePrimitives (target) {
  var sources = Array.from(arguments).slice(1)
  
  sources.forEach(function (source) {
    var ownKeys = Object.getOwnPropertyNames(source)
    var primitiveKeys = ownKeys.filter(filterPrimitives, source)
    
    primitiveKeys.forEach(function (key) {
      target[key] = source[key]
    })
  })

  return target
}

var target = {};

var source = {
  a: 'test',
  b: /test/,
  c: 5,
  d: null,
  e: undefined,
  f: {},
  g: []
}

clonePrimitives(target, source, { a: 'override' })

console.log(target)

If you want a more efficient approach, use for loops instead of forEach():

function clonePrimitives (target) {
  var i, j, source, ownKeys, key

  for (i = 1; i < arguments.length; i++) {
    source = arguments[i]
    ownKeys = Object.getOwnPropertyNames(source)

    for (j = 0; j < ownKeys.length; j++) {
      key = ownKeys[j]

      if (!(source[key] instanceof Object)) {
        target[key] = source[key]
      }
    }
  }

  return target
}

var target = {};

var source = {
  a: 'test',
  b: /test/,
  c: 5,
  d: null,
  e: undefined,
  f: {},
  g: []
}

clonePrimitives(target, source, { a: 'override' })

console.log(target)

And lastly, an equivalent ES6 approach that makes things a little nicer:

function clonePrimitives (target) {
  for (let source of Array.from(arguments).slice(1)) {
    for (let key of Object.getOwnPropertyNames(source)) {
      if (!(source[key] instanceof Object)) {
        target[key] = source[key]
      }
    }
  }

  return target
}

let target = {};

let source = {
  a: 'test',
  b: /test/,
  c: 5,
  d: null,
  e: undefined,
  f: {},
  g: []
}

clonePrimitives(target, source, { a: 'override' })

console.log(target)
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153