突变何时会成为副作用?

时间:2019-04-22 17:30:40

标签: javascript functional-programming

我遇到了以下未标记为功能的How to break on reduce,但包含了很多关于数组突变为功能否的讨论。

main answer对数组进行了变异以使其尽早脱离迭代器,但是可以通过将拼接的项目推回来轻松地将其恢复到其原始状态,这是一个有点可疑的解决方案,并且可以说完全没有功能。 / p>

但是,如果可以对项目进行修改(变异),那么许多算法都将获得显着优势

关于Java脚本(单线程(无工作者),也没有代理),如果修改只是暂时存在,是否将其视为变异?还是在函数返回后突变才是副作用?

以下功能是变种人吗?

function mutateAndRepair(arr) {  // arr is an array of numbers
    arr[0]++;
    arr[0]--;
}
  • 该数组包含1个或多个项目。
  • 数组的第一项(索引0)是最大安全整数范围内的数字。
  • 该数组不是共享缓冲区
  • 代理未监视数组

我认为这不是变异,因为变异仅在函数执行时存在,并且由于JS阻止,因此没有其他代码能够看到变异,因此没有副作用。

考虑到约束,这是否符合JavaScript编码人员使用的常见功能范例?

1 个答案:

答案 0 :(得分:5)

++--运算符正在变异,它们彼此不能完全精确地反转。引用2017 standard

  

12.4.4.1运行时语义:评估
   UpdateExpression LeftHandSideExpression ++

     
      
  1. lhs是评估LeftHandSideExpression的结果。
  2.   
  3. oldValue? ToNumber(? GetValue(lhs))
  4.   
  5. 使用与 + 运算符相同的规则,使newValue1oldValue相加的结果(请参见12.8.5) 。
  6.   
  7. 执行? PutValue(lhs, newValue)
  8.   
  9. 返回oldValue
  10.   

第二步很重要,因为它将值转换为number原语,但它与Number构造函数返回的Number对象之间也存在细微差别。

var arr = [new Number(1234)];

function mutateAndRepair(arr) {
  console.log(`the value before is ${arr[0]}`);
  arr[0]++;
  arr[0]--;
  console.log(`the value after is ${arr[0]}`);
}

arr[0].foo = 'bar';
console.log(`foo before is ${arr[0].foo}`);
mutateAndRepair(arr)
console.log(`foo after is ${arr[0].foo}`);

现在,我在这里有些厚脸皮,松散地解释了您对arr的第一项是“数字”的要求。并且可以肯定的是,您可以添加另一条规定,arr的值必须是“数字基元”,以排除这种确切的突变形式。

还有另一个更微妙的地方。 -00实际上在除Object.is之外的所有方式中都被视为相同的值:

var arr = [-0];

function mutateAndRepair(arr) {
  console.log(`the value before is ${arr[0]}`);
  arr[0]++;
  arr[0]--;
  console.log(`the value after is ${arr[0]}`);
}

console.log(`is zero before ${Object.is(0, arr[0])}`);
mutateAndRepair(arr)
console.log(`is zero after ${Object.is(0, arr[0])}`);

好的,您可以添加一个要求,即arr的第一项不是-0。但是所有这类都没有抓住重点。您可能会争辩说,如果您只是声明将忽略将观察到突变的任何情况,那么几乎任何方法都是不可突变的。

  

考虑到约束,这是否符合JavaScript编码人员使用的常见功能范例?

我不会(em>不)认为此代码遵循功能性编码原则,如果这是项目的目标,甚至可能会在代码审查中拒绝它。在所有代码路径中,如何或是否可以确保不变性的实质不是那么多,而是它依赖于内部变异的事实使我认为该代码无法正常工作。我已经看到伪功能代码中出现了许多错误,这些错误在mutaterepair步骤之间发生异常,这当然会导致明显和意外的副作用,即使您有catch / finally块来尝试恢复状态,那里也可能发生异常。这也许只是我的看法,但我认为不变性是更大的功能 style 的一部分,而不仅仅是给定功能的技术特征。