函数式 JavaScript:避免参数突变的良好做法?

Functional-style JavaScript: good practice to avoid argument mutation?

这是一个比较笼统的问题。函数式编程提倡程序是关于通过函数转换数据的想法,应该避免这种突变(除非可能在函数内,函数被视为抽象的基本单元)。

但是在这个程序中:

function foo (bar) {
  bar.k1 = "bananas";
  return bar;
}

var o = { k1: "apples", k2: "oranges"};
var p = foo(o);

外部变量 o 在 foo 中发生了变化,因为 bar 是对 o 的引用,最后,o === p(它们引用同一个对象)。但是功能范式更希望 p 是新数据。

显而易见的解决方案是克隆参数(例如使用 underscore/lodash 的 _.clone):

function foo (_bar) {
  var bar = _.clone(_bar);
  bar.k1 = "bananas";
  return bar;
}

但我想知道这是否是思考这个问题的正确方法。从 FP 的角度来看,如果对象将发生变异,您认为克隆作为参数传递的对象是一个好习惯吗? (我知道并非所有对象都可以轻松克隆,如果有的话,但让我们坚持简单的情况)。你的想法?

理想情况下,函数在每次调用时都应该 return 一个全新的对象。显然出于性能原因它不是很好,这就是为什么 persistent data structures exist. There are a few libraries for JS; immutable-js 可以说是最受欢迎的。

否则改变对象没问题,在 JS 中这是常见的做法,因为不是每个项目都会立即受益于持久数据结构,加上库的重量。

另请注意,在 JavaScript 中,所有内容均按值传递,但值本身可以包含引用。