Is there a proper way to clone certain primitive p

2019-09-15 18:13发布

问题:

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?

回答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);



回答2:

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.



回答3:

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)