【问题标题】:Object.assign(...as) changes input parameterObject.assign(...as) 更改输入参数
【发布时间】:2020-02-03 18:58:51
【问题描述】:

Object.assign(...as) 似乎更改了输入参数。示例:

const as = [{a:1}, {b:2}, {c:3}];
const aObj = Object.assign(...as);

我将一个对象字面量数组解构为 assign 函数的参数。 我省略了console.log 语句。这是节点 13.7 的标准输出:

和之前一样赋值:[ { a: 1 }, { b: 2 }, { c: 3 } ]

aObj: { a: 1, b: 2, c: 3 }

分配后:[ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

读者可能会注意到as 的第一个元素已整体更改。 将新数组 bs 元素更改为不可变对象(使用 freeze

const bs = [{a:1}, {b:2}, {c:3}];
[0, 1, 2].map(k => Object.freeze(bs[k]));
const bObj = Object.assign(...bs);

导致错误:

TypeError: 无法添加属性 b,对象不可扩展 在 Function.assign ()

这表明参数确实正在改变。

真正让我感到困惑的是,即使将我的数组 cs 绑定到一个函数中(我认为你在 JS 中称之为闭包)

const cs = [{a:1}, {b:2}, {c:3}];
const f = (xs) => Object.assign(...xs);
const g = () => f(cs);                            

const cObj = g();

返回:

cs 分配前:[ { a: 1 }, { b: 2 }, { c: 3 } ] cObj: { a: 1, b: 2, c: 3 } 赋值后的cs:[ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]

这里出了什么问题?以及如何安全地使用Object.assign 而不会破坏它的第一个参数?

【问题讨论】:

标签: javascript


【解决方案1】:

Object.assign 不是纯函数,它会覆盖其第一个参数target

这是它在MDN上的条目:

Object.assign(目标, ...来源)

参数

目标

目标对象——源属性的应用对象,修改后返回。

来源

源对象 - 包含您要应用的属性的对象。

返回值

目标对象。

关键短语是“[目标]在修改后返回”。为避免这种情况,请将空对象文字 {} 作为第一个参数传递:

const aObj = Object.assign({}, ...as);

【讨论】:

  • 这里也没有“咖喱函数”。
  • 关于您的未解决问题:试试immutable.js
  • 另一个我更常与副作用联系在一起的术语是procedure。但你真的应该写“…不是纯函数”。
  • "任何函数都可以对作为参数传入的对象进行修改。"确实是的。但这确实是一件坏事。即使是在 Fortran 77 中也令人不悦。函数(有副作用)不应该触及它们的参数,使用procedure 这样做。 Object.assign 也返回了修改后的第一个参数这一事实更加具有误导性。现在,您的评论指出了为什么人们可能会这样做。由于写入o = Object.assign(o, ...as);o 绑定到一个新对象(更改引用),而在const rubbishO = Object.assign(o, ...as) 中更改它而不更改o 的绑定。
  • @Bergi 我认为它不是一个 pure 函数,即没有副作用,这一点非常清楚。我在考虑程序与功能的关系。现在,既然它引起的争议多于它的价值,那么如何编辑它。让我们试试…… 附言:很高兴在这里见到你,Bergi,在过去的几周里,我在这里读了很多你的答案。对于那些只有笨拙的 ES6 之前的代码作为答案的老问题,在获得当前答案方面做得很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 2018-08-10
  • 1970-01-01
  • 2022-12-10
  • 1970-01-01
相关资源
最近更新 更多