Lodash:从多个构造单个对象 - 合并/覆盖属性

Oli*_*ent 20 javascript lodash

注意:我在lodash下提交了这个问题,因为我很确定它可以帮助我很好地解决这个问题,但是现在还没有把它放在它上面

我有一个描述不同用户角色及其权限的对象;

我会像"这样"定义10-15个角色(这不反映应用程序代码,但问题本身):

    var role1 = {
    views: {
        v1: {access: true},
        v2: {access: false},
        v#: {access: false}
    }
}

var role2 = {
    views: {
        v1: {access: false},
        v2: {access: true},
        v3: {access: true},
    }
}
Run Code Online (Sandbox Code Playgroud)

连接的用户将具有多个角色; 在那个例子中它可能是['role1', 'role2'],并且我需要构造一个单独的permissions对象,它将是所有用户角色中定义的所有道具的组合.

它基本上是基于白名单的,其中所有"真实"属性应该覆盖任何被定义为false的属性.因此,预期结果应该是:

permissions = {
    views: {
        v1: {access: true},
        v2: {access: true},
        v2: {access: true}
    }
}
Run Code Online (Sandbox Code Playgroud)

我不太确定如何在不依赖疯狂的嵌套循环的情况下解决这个问题

这是JSBin的一个起点:http://jsbin.com/usaQejOJ/1/edit?js,console

谢谢你的帮助!

ada*_*que 42

Lodash有一些方法可以帮助优雅地解决这个问题.

首先,merge方法.它需要多个源对象,并以递归方式将它们的属性合并到一个目标对象中.如果两个对象具有相同的属性名称,则后一个值将覆盖前者.

这几乎是我们想要的; 它会将您的角色对象合并为一个对象.我们不想要的是覆盖行为; 我们希望true值始终覆盖它们false.幸运的是,你可以传入一个自定义合并函数,merge当两个对象具有相同的键时,lodash 将使用它来计算合并值.

我们将逻辑上的一个自定义函数编写OR在一起(而不是允许以后的false值覆盖trues.),这样如果任一值true,则得到的合并值将是true.

因为我们的对象是嵌套的,所以我们需要确保我们的自定义合并函数只OR在比较布尔值时才这样做.在比较对象时,我们希望对其属性进行正常合并(再次使用我们的自定义函数进行合并).它看起来像这样:

function do_merge(roles) {

  // Custom merge function ORs together non-object values, recursively
  // calls itself on Objects.
  var merger = function (a, b) {
    if (_.isObject(a)) {
      return _.merge({}, a, b, merger);
    } else {
      return a || b;
    }
  };

  // Allow roles to be passed to _.merge as an array of arbitrary length
  var args = _.flatten([{}, roles, merger]);
  return _.merge.apply(_, args);
}

do_merge([role1, role2, role3]);
Run Code Online (Sandbox Code Playgroud)

Lodash以另一种方式提供帮助:您可能会注意到_.merge不接受一组对象合并在一起的文档; 你必须作为参数传递它们.但在我们的例子中,数组非常方便.

为了解决这个问题,我们将使用JavaScript的apply方法,它允许您通过将其参数作为数组传递来调用方法,以及Lodash的方便flatten方法,该方法采用可能包含嵌套数组的数组(如[1, [2, 3], [4, 5]]- )并将其展平为[1, 2, 3, 4, 5].

因此,我们将收集flattened数组中所需的所有参数,然后将apply它们收集起来merge!

如果您的对象嵌套的非常深,那么您可能会merger像这样以递归方式溢出堆栈,但对于您的对象,这应该可以正常工作.

  • 哇我无法希望答案解释得那么好!百万谢谢! (3认同)
  • OMG非常感谢这个答案! (2认同)