[译] 利用 Immutability(不可变性)编写更为简洁高效的代码

简介: 本文讲的是[译] 利用 Immutability(不可变性)编写更为简洁高效的代码,不可变性是函数式编程中的一部分,它可以使你写出更安全更简洁的代码。我将会通过一些 JavaScript 的例子来告诉你如何达到不可变性。
本文讲的是[译] 利用 Immutability(不可变性)编写更为简洁高效的代码,

不可变性是函数式编程中的一部分,它可以使你写出更安全更简洁的代码。我将会通过一些 JavaScript 的例子来告诉你如何达到不可变性。

根据维基( 地址 ):

一个不可变对象(不能被改变的对象)是指在创建之后其状态不能被更改的对象,这与在创建之后可以被更改的可变对象(可以被改变的对象)相反。在某些情况下,一个对象的外部状态如果从外部看来没有变化,那么即使它的一些内部属性更改了,仍被视为不可变对象。

不可变的数组

数组是了解不可变性如何运作的一个很好的起点。我们来看一下。

const arrayA = [1, 2, 3];
arrayA.push(4);

const arrayB = arrayA;
arrayB.push(5);

console.log(arrayA); // [1, 2, 3, 4, 5]
console.log(arrayB); // [1, 2, 3, 4, 5]

例子中 arrayB 是 arrayA 的引用,所以如果我们通过 push 方法向任意数组中添加一个值 5,那么就会间接影响到另外一个,这个是违反不可变性的原则的。

我们可以通过使用 slice 函数以达到不可变性,进而优化我们的例子,此时代码的行为是完全不一样的。

const arrayA = [1, 2, 3];
arrayA.push(4);

const arrayB = arrayA.slice(0);
arrayB.push(5);

console.log(arrayA); // [1, 2, 3, 4]
console.log(arrayB); // [1, 2, 3, 4, 5]

这才是我们要的,代码不改变其它的值。

记住:当使用 push 来给数组添加一个值时,你在改变这个数组,因为这样可能会影响代码里的其他部分,所以你想要避免使变量值发生改变。slice 会返回一个复制的数组。

函数

现在你知道了如何避免改变其它的值。那如何写「纯」的函数呢?纯函数是指不会产生任何副作用,也不会改变状态的函数。

我们来看一个示例函数,其原理与前面数组示例的原理相同。首先我们写一个会改变其它值的函数,然后我们将这个函数优化为「纯」函数。

const add = (arrayInput, value) => {
  arrayInput.push(value);

  return arrayInput;
};
const array = [1, 2, 3];

console.log(add(array, 4)); // [1, 2, 3, 4]
console.log(add(array, 5)); // [1, 2, 3, 4, 5]

于是我们又一次改变输入的变量的值,这使得这个函数变得不可预测。在函数式编程的世界里,有一个关于函数的铁律:函数对于相同的输入应当返回相同的值。

上面的函数违反了这一规则,每次我们调用 add 方法,它都会改变数组变量导致结果不一样。

让我们来看看怎样修改 add 函数来使其不可变。

const add = (arrayInput, value) => {
  const copiedArray = arrayInput.slice(0);
  copiedArray.push(value);

  return copiedArray;
};

const array = [1, 2, 3];
const resultA = add(array, 4);
console.log(resultA); // [1, 2, 3, 4]
const resultB = add(array, 5);
console.log(resultB); // [1, 2, 3, 5]

现在我们可以多次调用这个函数,且相同的输入获得相同的输出,与预期一致。这是因为我们不再改变 array 变量。我们把这个函数叫做“纯函数”。

注意: 你还可以使用 concat,来代替 slice 和 push
即:arrayInput.concat(value);

我们还可以使用 ES6 的扩展语法,来简化函数。

const add = (arrayInput, value) => […arrayInput, value];

并发

NodeJS 的应用有一个叫并发的概念,并发操作是指两个计算可以同时的进行而不用管另外的一个。如果有两个线程,第二个计算不需要等待第一个完成即可开始。

1*LS1VkNditQwYMJvtIPAhdg.png

可视化的并发操作

NodeJS 用事件循环机制使并发成为可能。事件循环重复接收事件,并一次触发一个监听该事件的处理程序。这个模型允许 NodeJS 的应用处理大规模的请求。如果你想学习更多,读一下这篇关于事件循环的文章

不可变性跟并发又有什么关系呢?由于多个操作可能会并发地改变函数的作用域的值,这将会产生不可靠的输出和导致意想不到的结果。注意函数是否改变它作用域之外的值,因为这可能真的会很危险。

下一步

不可变性是学习函数式编程过程中的一个重要概念。你可以了解一下由 Facebook 开发者写的 ImmutableJS,这一个库提供一些不可变的数据结构,比如说 MapSet、和 List

1

点击 让更多的人可以在 Medium 上看见这篇文章,感谢阅读。






原文发布时间为:2017年5月31日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
目录
相关文章
|
3月前
|
开发框架 .NET 编译器
C# 10.0中Lambda表达式的改进:更简洁、更灵活的代码编写体验
【1月更文挑战第21天】随着C#语言的不断发展,Lambda表达式作为一种简洁、高效的函数式编程工具,在C# 10.0中迎来了重要的改进。本文将详细探讨C# 10.0中Lambda表达式的新特性,包括参数类型的推断增强、自然类型的Lambda参数以及Lambda表达式的属性改进等。这些改进不仅简化了Lambda表达式的编写过程,还提升了代码的可读性和灵活性,为开发者带来了更优质的编程体验。
|
16天前
|
程序员 Go 数据中心
掌握Go语言:探索Go语言中的代码块和作用域,增强程序灵活性与可维护性(5)
掌握Go语言:探索Go语言中的代码块和作用域,增强程序灵活性与可维护性(5)
|
18天前
|
Java API 开发者
Java中的Lambda表达式:简洁、灵活、高效
Lambda表达式是Java 8引入的重要特性,它为Java编程带来了更简洁、更灵活、更高效的编程方式。本文将深入探讨Lambda表达式的语法、特性以及在实际开发中的应用,帮助读者更好地理解和应用Lambda表达式。
|
2月前
|
算法 程序员 PHP
编写魅力十足的代码:优化可读性、维护性和性能的关键
本篇汇总了平时在工作开发中常遇到的业务逻辑的优雅写法,也汇总了自己还是新人时,拿到一个业务不知道怎么下手的痛点,依稀记得那时候总感觉自己写的代码不规范。 写完之后,感觉还是美好的,又学到东西了。
|
3月前
|
算法 安全 测试技术
函数式编程:简洁与效率的完美结合
函数式编程:简洁与效率的完美结合
|
6月前
|
Go 开发者
Go语言代码优雅之道:简洁、清晰示例驱动
Go语言代码优雅之道:简洁、清晰示例驱动
57 0
|
8月前
|
存储 Java 开发者
我选择使用Lambda,就是因为其简洁、灵活、高效!
我选择使用Lambda,就是因为其简洁、灵活、高效!
57 0
|
10月前
|
设计模式 缓存 安全
简化代码,提高可维护性 Java外观模式解读,让你的代码优雅又高效
简化代码,提高可维护性 Java外观模式解读,让你的代码优雅又高效
74 0
|
Arthas 缓存 算法
如何写出高性能代码(二)巧用数据特性
同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员 不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。
150 0
如何写出高性能代码(二)巧用数据特性