2
project = {id: 1}
milestone = { id: 1, name: "milestone a" }
tasks = [{ name: 'task a' }, { name: 'task b' }]

我需要从上面的三个对象中创建一个对象,如下所示:

project = { id:1, milestone: {id: 1, name: "milestone a", tasks: [...]} }

我尝试了 project.milestone =里程碑,...但是如果我有很多变量和分配,就无法使用。

所以我的问题是,如何在另一个对象中包含一个对象并修改父对象,以便:

a = {id: 1}
b = {id: 2}
a.magic_method(b) // => {id: 1, b: {id: 2}}
4

5 回答 5

2

你可以$.extend

$.extend(project, {milestone: milestone}, {tasks: tasks});

这是一个例子:http: //jsfiddle.net/hDWef/

于 2013-07-12T12:57:49.880 回答
1

用这个

$.extend(project, {milestone: $.extend(milestone,{tasks:tasks})});
于 2013-07-12T13:05:23.500 回答
1

编辑:

哦,我刚刚意识到,您想tasks合并milestonemilestone合并到项目中。

在这种情况下,您必须合并一个合并的对象。

但是像@Amberlamps 和@Elias Van Ootegem 建议的那样,从一开始就设置这样的对象结构会更容易。

我更新了答案

Edit2:更改了类型检查以使用instanceof,因为{}.toString.call(o)返回对象 ClassName,对于 nodeElement 和“[object global]”可以是任何东西window


您可以编写一个合并函数,将多个对象的属性合并为一个。

var merge = (function () {
    var initThis = this;
    return function () {
        var len = arguments.length - 1,
            srt, tmp;
        if ("function" === typeof arguments[arguments.length - 1]) srt = arguments[arguments.length - 1];
        else {
            srt = function (a, b, prop) {
                if (!prop) return a;
                return a[prop];
            };
            len++;
        }
        var merge = this === initThis ? {} : this;
        for (var i = 0; i < len; i++) inner(arguments[i], merge);

        function inner(obj2, obj1) {
            if (obj2 instanceof Array) {
                if (!obj1) obj1 = [];
                if (typeof obj1 != "object") obj1 = (tmp = srt(obj1, obj2, null), tmp) === obj2 ? [] : tmp;
                for (var i = 0; i < obj2.length; i++) if (!obj1[i] && typeof obj2[i] == "object") obj1[i] = inner(obj2[i]);
                    else if (obj1[i] && typeof obj2[i] == "object") obj1[i] = inner(obj2[i], obj1[i]);
                else if (obj1[i]) obj1[i] = srt(obj1, obj2, i) || obj1[i];
                else obj1[i] = obj2[i];
            } else if (obj2 instanceof Object) {
                if (!obj1) obj1 = {};
                if (typeof obj1 != "object") obj1 = (tmp = srt(obj1, obj2, null), tmp) === obj2 ? {} : tmp; //If obj2 is returned, set to empty obj to allow deep cloning
                for (var prop in obj2) {
                    var isObj = "object" === typeof obj2[prop];
                    if (!obj1[prop] && isObj) obj1[prop] = inner(obj2[prop]);
                    else if (obj1[prop] && isObj) obj1[prop] = inner(obj2[prop], obj1[prop]);
                    else if (obj1[prop]) obj1[prop] = srt(obj1, obj2, prop) || obj1[prop];
                    else obj1[prop] = obj2[prop];
                }
            } else {
                throw new SyntaxError ("expected " + obj2 + " to be of type object");
            }
            return obj1;
        }
        return merge;
    };
})();

合并函数接受n个参数,其中最后一个可以是消歧函数,当当前合并对象的2个属性相同时调用该函数。

使用 3 个参数调用此消歧函数:

  • a
    • 属性被合并的当前第一个对象。
  • b
    • 属性被合并的当前第二个对象。
  • prop
    • 被合并的属性的名称

函数的返回值将分配给当前的合并属性。

例如return a[prop],如果存在冲突,将始终分配第一个对象的值。

如果没有函数作为最后一个参数传递,则默认行为是:保留第一个 Object 的值。

现在我们必须调用mergeand milestonetasks然后merge project使用合并的milestoneObject,它看起来像这样。

project = {id: 1};
milestone = { id: 1, name: "milestone a" };
tasks = [{ name: 'task a' }, { name: 'task b' }];


var merged = merge (project,{milestone: merge (milestone , {tasks:tasks} )});
                                       //^^^ mergeception
                                                           //^^^ Wrap it because you want the complete 'tasks' object, not merge the properties this time.

console.log (JSON.stringify(merged));
/* {
"id": 1,
"milestone": { //<- milestone in merged/project
    "id": 1,
    "name": "milestone a",
    "tasks": [{          //<- tasks in milestone
        "name": "task a"
    }, {
        "name": "task b"
    }]
  }
} */

你可以看到它返回一个合并的对象。

这是一个关于 JSBin的演示

或者如果你想要 jQuery 的方式..

var merged = $.extend(project, {milestone : $.extend (milestone, {tasks:tasks}) });

于 2013-07-12T13:12:57.113 回答
1

无法知道变量的人类可读名称是什么。所以你会发现没有任何神奇的功能可以满足你的要求。

此外,您永远不需要这样的函数,因为您决定了变量的名称。因此,与其寻找一个神奇的函数,不如把你的变量名写成一个对象属性:

var a = { id: "idA" };
var b = { id: "idB" };

a.b = b;
// it does not get more simple than that!
于 2013-07-12T13:17:56.650 回答
0

这应该实现你所追求的。我将它创建为一个函数,以便您可以重用它。

想法:

function (parent, {object list of children to combine to parent});

来源:

var project = {id: 1};
var milestone = { id: 1, name: "milestone a" };
var tasks = [{ name: 'task a' }, { name: 'task b' }];
var finalList;

function combine(parent, combineList) {
    var len = combineList.length;
    var returnList = {}

    // Add values from the parent, in our case 'project'
    for (prop in parent) {
        returnList[prop] = parent[prop];
    }

    // Add in children
    for (obj in combineList) {
        returnList[obj] = combineList[obj];
    }

    return returnList;
}

finalList = combine(
    project, {
        'milestone': milestone, 
        'tasks': tasks
    });

console.log(finalList);
// finalList = {"id":1,"milestone":{"id":1,"name":"milestone a"},"tasks":[{"name":"task a"},{"name":"task b"}]} 
于 2013-07-12T13:39:06.630 回答