【问题标题】:Underscore: Array of objects to flat object. What's the magic?下划线:对象数组到平面对象。有什么魔力?
【发布时间】:2014-11-11 01:32:56
【问题描述】:

我正在转换这个对象数组:

[
  {
    first: {
      blah: 1,
      baz: 2
    }
  },
  {
    second: {
      foo: 1,
      bar: 2
    }
  }
]

对于这个更简单的平面对象:

{
  first: {
    blah: 1,
    baz: 2
  },
  second: {
    foo: 1,
    bar: 2
  }
}

我发现使用 Underscore/LoDash 的两种最简单的方法是:

// Using reduce and extend
_.reduce(myArray, _.extend)

// Using assign and apply
_.assign.apply(_, myArray);

完整的代码记录在 JSBin 中:http://jsbin.com/kovuhu/1/edit?js,console

我已经阅读了很多关于 apply/bind/call/assign/reduce/extend 的文档……但我就是无法理解幕后实际发生的事情。

谁能帮我了解一下这两种单线表演魔术的秘密?

【问题讨论】:

  • 他们执行黑魔法,因为他们变异你的第一个对象。应该是_.reduce(myArray, _.extend, {})(这对extend(extend({}, myArray[0]), myArray[1])很友好)

标签: javascript underscore.js lodash


【解决方案1】:

为了理解这一点,让我们创建一个简单版本的 assign(别名扩展)。我们将只接受一个参数,我们将其称为 source,并将其添加到我们的结果中。

function assign(result, source) {

  var keys = Object.keys(source),
    length = keys.length;

  for (var i=0 ; i < length; i ++) {
    var key = keys[i];
    result[key] = source[key];
  }

  return result;
}

现在让我们将输入分成几部分:

var a = {
  first: {
    blah: 1,
    baz: 2
  }
}

var b = {
  second: {
    foo: 1,
    bar: 2
  }
}

var input = [a, b];

现在我们可以调用reduce了:

_.reduce(input, assign);

reduce 会调用 assign 两次:

assign(result, a);
// assigns the (key, value) pair ("first", {blah: 1, baz: 2}) to result

assign(result, b);
// assigns the (key, value) pair ("second", {foo: 1, bar: 2}) to result

Talk 很便宜,给我看代码: http://jsbin.com/hexiza/3/edit?js,console

您可以在Lo-Dash source code 中看到如何使用 createAssigner() 和 baseAssign() 实现分配。

【讨论】:

  • 感谢 Andrew 展示了做同样事情的另一种方式(减少 + 分配)。例子很清楚。
【解决方案2】:

reduce 获取对象中数组/属性中的所有值,aggregates them。在这种情况下,extend 被传递给reduce,这意味着你传递了一个function(a,b) 用于扩展值a(每个步骤都带有)对象b 的所有属性(数组中的每个值) , 一次一个)。在您的一个衬里,下划线的reduce 遍历您的数组,从一个对象 {} 开始,并在它沿着您的输入数组遍历时简单地将所有数组元素属性转储到该对象中。在普通的 JS 中,它会是这样的:

var thing = {};
var deeparray = [{...}, {...}, {...}];
deeparray.forEach(function(v) {
  Object.keys(v).forEach(function(k) {
    thing[k] = v[k];
  }
}); 
return thing;

assign (not found in underscore) 做同样的事情,获取一组对象并将它们全部压缩在一起。从字面上看,这是它唯一做的事情。调用 _assign.apply(_, myArray) 与 _ 调用 this.assign(myArray) 相同 - apply 是用于调用函数的基本 JavaScript 函数,同时“手动覆盖”关键字 this 在该函数中的含义。 _.assign.apply(_,myArray) 与调用 _.assing(myArray) 相同,除了额外保证 this 将是 lodash,而不是一些随机函数范围的上下文。

【讨论】:

  • 谢谢,我现在知道reduce 和extend 发生了什么。不确定我是否完全理解为什么_.assign(myArray) 不起作用,我们需要用_ 覆盖this。你能扩展一下吗?
  • 该函数是从不同的范围内部绑定的,所以如果你不使用apply,“this”指的是顶级函数范围,从我在源代码中可以看到。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-01
  • 2016-10-09
相关资源
最近更新 更多