javascript - 为什么 _.merge 中的第一个对象会更新为当前值?

标签 javascript object lodash

假设我有三个对象。

const x = { val: 1 };
const y = { val: 2 };
const z = { val: 3 };

const mergedObj = _.merge(x,y,z);
// x = { val: 3 };
// y = { val: 2 };
// z = { val: 3 };
// mergedObj = { val: 3 };

为什么lodash的merge函数中第一个对象将对象x的值改为3,而对象y的值仍然为2?我认为所有对象都会保留相同的键值对,因为 _.merge 函数会创建一个新对象?我的假设错了吗?

最佳答案

Lodash 改变第一个参数而不是创建一个全新的对象。每个后续参数都按顺序应用于第一个参数之上,但它们本身保持不变。

我们可以通过创建 JavaScript setter 函数来演示这一点。每次“设置”属性时都会调用此方法(因此得名)。

let merge1 = { val: 1 };
let merge2 = { val: 2 };
let merge3 = { val: 3 };

let mergeTarget = {
	val:0,
  set val(name) {
    console.log("Setting with:" + name);
  }
}

_.merge(mergeTarget,merge1,merge2, merge3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

您会看到 mergeTarget 上的 setter 不是被调用一次而是被调用了三次,每个后续属性都按顺序调用:

Setting with:1
Setting with:2
Setting with:3

明确一点,Lodash 确实 返回对最终值的引用,这在使用合并内联等情况下很有用。例如(使用人为的例子):

someArray.map(_.merge(mappingFunction, properties))

但是,正如您所注意到的,此返回值只是对已更改的第一个参数的引用。

为什么?

至于更深层次的问题,为什么 lodash 这样做...这是一个很好的问题,毕竟通常避免 impure functions 是有意义的对于一个简单的效用函数。真的必须问问 lodash 开发人员以及在他们之前设置这种做法的 underscore 开发人员。

但我们可以很容易地想到一些很好的理由,为什么它是这样实现的,为什么它仍然存在。

<强>1。易于使用/风格。

Lodash/underscore 的部分吸引力在于它们提供了方便且定义明确的实用函数,这些函数易于自由使用。在某种程度上,它们感觉像是 JavaScript 本身的语法糖。在您只需要合并一个对象的情况下,这样就不用担心或弄乱代码了。

例如你可以这样做:

myComponent.updateConfig = function(update){
   _.merge(myComponent.config, update)
}

这比担心返回值要简洁一点。考虑到副作用是明确和明确的,像这样使用它并不是一件坏事。

然而,这可以说是最不重要的原因。

<强>2。性能。

除非必要,否则避免创建过多对象是一个明智的默认设置。

JavaScript 的默认行为是通过引用传递对象,它不要求任何聪明的方法来对对象的一部分进行写时复制突变。如果您需要创建对象的修改副本,同时保持原始对象不变,唯一的方法是复制整个对象,然后对副本进行修改。

当处理只有几个属性的简单对象时,这不是问题,但假设您有一个具有数百个属性的复杂对象,并且您在应用程序的更新周期中逐步合并添加(例如)。不难想象优化和内存泄漏可能成为问题的情况。

<强>3。很容易避免。

有些情况下不希望改变对象,我们更喜欢纯函数行为。然而,通过简单地将空对象作为第一个参数传递来创建此行为非常容易。

const x = { val: 1 };
const y = { val: 2 };
const z = { val: 3 };

const result = _.merge({},x,y,z);
console.log(x.val) //will return 1
result.val = 5
console.log(x.val) //will still return 1

关于javascript - 为什么 _.merge 中的第一个对象会更新为当前值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56856584/

相关文章:

Javascript 无法正确排序 DECIMAL 数字

javascript - 如何自动保存动态生成的 HTML SVG 元素

powershell - 静态的PowerShell对象

java - 使用安全管理器保护对象

javascript - 按两个最接近的字段对js数组进行排序

javascript - 通过将对象数组与数组进行比较来创建新数组

arrays - 如何使用 Lo-Dash 对数组进行降序排序?

javascript - 如何使用 Angular UI-Router 获取状态?

javascript - 只计算一次具有更多相等单元格的行

javascript - 如何通过使用日期作为键对象修改此对象的结构,并将所有在同一日期完成的事件与其配对