我遇到了以下未标记为功能的How to break on reduce,但包含了很多关于数组突变为功能否的讨论。
main answer对数组进行了变异以使其尽早脱离迭代器,但是可以通过将拼接的项目推回来轻松地将其恢复到其原始状态,这是一个有点可疑的解决方案,并且可以说完全没有功能。 / p>
但是,如果可以对项目进行修改(变异),那么许多算法都将获得显着优势
关于Java脚本(单线程(无工作者),也没有代理),如果修改只是暂时存在,是否将其视为变异?还是在函数返回后突变才是副作用?
以下功能是变种人吗?
function mutateAndRepair(arr) { // arr is an array of numbers
arr[0]++;
arr[0]--;
}
我认为这不是变异,因为变异仅在函数执行时存在,并且由于JS阻止,因此没有其他代码能够看到变异,因此没有副作用。
考虑到约束,这是否符合JavaScript编码人员使用的常见功能范例?
答案 0 :(得分:5)
++
和--
运算符正在变异,它们彼此不能完全精确地反转。引用2017 standard:
12.4.4.1运行时语义:评估
UpdateExpression : LeftHandSideExpression ++
- 让
lhs
是评估LeftHandSideExpression
的结果。- 让
oldValue
为? ToNumber(? GetValue(lhs))
。- 使用与 + 运算符相同的规则,使
newValue
为1
与oldValue
相加的结果(请参见12.8.5) 。- 执行
? PutValue(lhs, newValue)
。- 返回
oldValue
。
第二步很重要,因为它将值转换为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
的值必须是“数字基元”,以排除这种确切的突变形式。
还有另一个更微妙的地方。 -0
和0
实际上在除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>不)认为此代码遵循功能性编码原则,如果这是项目的目标,甚至可能会在代码审查中拒绝它。在所有代码路径中,如何或是否可以确保不变性的实质不是那么多,而是它依赖于内部变异的事实使我认为该代码无法正常工作。我已经看到伪功能代码中出现了许多错误,这些错误在mutate
和repair
步骤之间发生异常,这当然会导致明显和意外的副作用,即使您有catch
/ finally
块来尝试恢复状态,那里也可能发生异常。这也许只是我的看法,但我认为不变性是更大的功能 style 的一部分,而不仅仅是给定功能的技术特征。