最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Elegant way to code partially copy objects in Javascript? - Stack Overflow

programmeradmin1浏览0评论

I have a javascript object that represents form fields. about 70% of these fields have to be copied in some objects for sending to server, other fields are for UI usage. Presently I clone objects by manually creating assignments for each field, that result in rather not nice structures, as shown below. Note that I would keep field names identical for parts being copied.

var contData = {
                ContainerType: data.ContainerType,
                ProjectIds: data.ProjectIds,
                PrivateToProjects: data.PrivateToProjects,
                DimensionType:data.DimensionType,
                MetricsX: data.MetricsX,
                MetricsY: data.MetricsY,
                Parent:data.Parent,
                ContainerName:data.Prefix
            };

What would be the best way to code cloning part of object, just specifying list of fields to clone/not to clone, such as some useful helper function?

I also use angular and jquery.

I have a javascript object that represents form fields. about 70% of these fields have to be copied in some objects for sending to server, other fields are for UI usage. Presently I clone objects by manually creating assignments for each field, that result in rather not nice structures, as shown below. Note that I would keep field names identical for parts being copied.

var contData = {
                ContainerType: data.ContainerType,
                ProjectIds: data.ProjectIds,
                PrivateToProjects: data.PrivateToProjects,
                DimensionType:data.DimensionType,
                MetricsX: data.MetricsX,
                MetricsY: data.MetricsY,
                Parent:data.Parent,
                ContainerName:data.Prefix
            };

What would be the best way to code cloning part of object, just specifying list of fields to clone/not to clone, such as some useful helper function?

I also use angular and jquery.

Share Improve this question asked May 27, 2014 at 10:03 onkamionkami 9,44120 gold badges104 silver badges200 bronze badges 1
  • Yes. Have you tried writing such a helper function? It's quite trivial actually. I don't think there already is one in angular or jquery. – Bergi Commented May 27, 2014 at 10:20
Add a ment  | 

4 Answers 4

Reset to default 10

After ES6, you could

let { ContainerType, ProjectIds } = data  // the fields you want
let partiallyCopy = { ContainerType, ProjectIds }
console.log(partiallyCopy)  // { ContainerType: "...", ProjectIds: "..." }

And if you need most fields, you could

let { ContainerType, ProjectIds, ...rest } = data  // the fields you don't want
let partiallyCopy = rest
console.log(partiallyCopy)  // the object excludes ContainerType and ProjectIds

You could create a custom function to clone your object partially with a filter function.

It could be something like this as the very simple version.

function filteredClone(sourceObj, filterFunction){
  var destObj = {};
  for(var i in sourceObj){
    if(filterFunction(sourceObj[i])){
      destObj[i] = sourceObj[i];
    }
  }
  return destObj;
}

And you can call it like the following assuming that you don't want "name" and "surname" fields to be copied.

var dest = filteredClone(source, function(v){
   return ["name","surname"].indexOf(v) !== -1;
});

There are a couple of more sophisticated samples in the answers to the following question.

Deep clone without some fields

Dan's destructuring answer is good, but it still requires an assignment, making it less than ideal (however still possible) for lambda, or arrow-style, concatenation. It remains a great way to filter out object fields when passing parameters to a functions, for instance

Here's an alternative that you can embed in an expression and that doesn't use assignment side-effects:

wanted = ['ContainerType', 'ProjectIds', 'PrivateToProjects',
         'DimensionType', 'MetricsX', 'MetricsY', 'Parent', 'Prefix']

contData = Object.fromEntries(Object.entries(data).filter(x => wanted.includes(x[0]))))

The only state this requires is the wanted fields. If you want to preserve most fields in data, you can always use notWanted instead and negate the filter condition.

One method is to define properties on objects. IE9 is the first IE to support this.

var obj = {};
Object.defineProperty(obj, "no1", {enumerable: false, value: "", writable: true, configurable: true});
Object.defineProperty(obj, "no2", {enumerable: false, value: "", writable: true, configurable: true});

obj.yes1 = "foo";
obj.yes2 = "bar";
obj.no1 = "baz";
obj.no2 = "quux";

jsfiddle

99.9% of clone functions will loop over the keys, and only enumerable keys will show up, so they only copy enumerable keys. This is the same reason why, e.g. toString doesn't show up when looping over an object's keys.

This can be abstracted to allow defining data and temporary values.

function makeType(description, data) {
    if (arguments.length === 1) {
        return function (data) {
            return makeType.call(this, description, data);
        };
    }

    var obj = {};
    data = data || {};
    for (var key in description) {
        if (description[key] === true) {
            obj[key] = data[key]
        } else {
            Object.defineProperty(obj, key, {
                enumerable: false,
                value: data[key],
                writable: true,
                configurable: true
            });
        }
    }
    return obj;
}

var makeYesNo = makeType({
    yes1: true,
    yes2: true,
    no1: false,
    no2: false
});

var obj = makeYesNo({
    yes1: "foo",
    yes2: "bar",
    no1: "baz",
    no2: "quux"
})

fiddle

发布评论

评论列表(0)

  1. 暂无评论