当JavaScript没有提供任何明显的实现不变性的方法时,人们如何在JavaScript中实现不可变的数据结构?

我决定尝试使用函数式编程范式,因为我从几个来源听说并阅读了函数式编程创建的代码:

  • 我有更多的控制权。
  • 很容易测试。
  • 易于其他人阅读和关注。
  • 对我来说更容易阅读。

……谁不想要?我当然试过了。

我第一次尝试用 JavaScript 进行函数式编程

我对函数式编程的第一次尝试并不顺利。我从state 的角度考虑它,并在整个过程中维护应用程序状态,但是,我写了几行代码后很快就卡住了。我无法解决如何实现真正不可变的不可变数据结构,或者如何在我的数据结构中更改变量,当这些变量及其属性都是不可写时"_

当 JavaScript 不提供任何类型的显式不可变数据类型或支持时,当代 JavaScript 开发人员如何实现不可变数据结构来管理其应用程序的状态?

我正在寻找任何不可变数据结构的示例;以及如何实现允许我使用数据结构的功能来管理 JS 应用程序的状态。如果答案涉及使用 3rd 方库、其他语言或任何其他我认为非常好的工具。一个实际代码的例子会很棒,这样我就可以解释和理解一些东西。



Bellow 是我创建一个可以实现的不可变数据结构的可怕尝试。
虽然它不是很好的代码,但它展示了我想要完成的事情

'use strict';

const obj = {};

Object.defineProperties(obj, {
  prop_1: {
    value: (str) => {this.prop_3 = str};
    writable: false,
  },

  prop_2: {
    value: () => this.prop_3;
    writable: false,
  },

  prop_3: {
    value: '',
    writable: false,
  },
});

obj.prop_1('apples & bananas');

console.log(obj.prop_3);



/*

TERMINAL OUTPUT:

Debugger attached.
Waiting for the debugger to disconnect...
file:///home/ajay/Project-Repos/j-commandz/sandbox.js:19
      this.prop_3 = str;
                  ^

TypeError: Cannot assign to read only property 'prop_3' of object '#<Object>'
    at Object.set (file:///home/ajay/Project-Repos/j-commandz/sandbox.js:19:19)
    at file:///home/ajay/Project-Repos/j-commandz/sandbox.js:37:5

*/



回答

你是对的,Javascript(与Haskell & co. 不同)没有为不可变数据结构提供一流的支持(在 Java 中你会有关键字final)。这并不意味着您不能以不可变的方式编写代码或推理程序。

正如其他人所提到的,您仍然有一些本机 javascript API 可以帮助您实现不变性(ish),但是正如您已经意识到的那样,它们都没有真正解决问题(Object.freeze只能在浅层工作,const阻止您重新分配变量,但不能改变它, 等等。)。


那么,你怎么能做不可变的 JS 呢?

我想提前道歉,因为这个答案可能主要基于意见,并且不可避免地会因我自己的经验和思维方式而有缺陷。所以,请用少许盐选择以下内容,因为这只是我在这个主题上的两分钱。

我想说的是不变性主要是一种思维状态,在此之上您可以构建所有支持(或使其更易于使用)它的语言 API。

我之所以说“这主要是一种心态”,是因为您可以(某种程度上)用第三方库来弥补一流语言结构的不足(并且有一些非常令人印象深刻的成功案例)。

但是不变性是如何工作的呢?

嗯,它背后的想法是,任何变量都被视为固定的,任何突变都必须在新实例中解决,而原始实例input保持不变。

好消息是,这已经适用于所有 javascript 原语。

const input = 'Hello World';
const output = input.toUpperCase();

console.log(input === output); // false
const input = 'Hello World';
const output = input.toUpperCase();

console.log(input === output); // false

所以,问题是,我们如何能对待一切,因为它是一个原始的

...嗯,答案很简单,接受函数式编程的一些基本原则,并让第三方库

class User {
  name;

  setName(value) { this.name = value }
}
clas

const user = { name: 'Giuseppe' };

const setUserName = (name, user) => ({ ...user, name });

s User {
name;

setName(value) { this.name = value }
}
填补这些语


const user = { name: 'Giuseppe' };

const setUserName = (name, user) => ({ ...user, name });

言空白。

  1. state从他们的transition逻辑中分离出来:

只是

  1. 避免命令式方法并利用第三方专用库
import * as R from 'ramda';

const user = { 
  name: 'Giuseppe',
  address: {
    city: 'London',
  }
};


const setUserCity = R.assocPath(['address', 'city']);

const output = setUserCity('Verbicaro', user);

console.log(user === output); // recursively false

也许是我喜欢的一些库的注释

  1. Ramda提供不变性,并用您通常在任何f语言中找到的所有声明性好东西来丰富 js api (sanctuary-js和fp-ts也是伟大的成功案例)
  2. RxJS 使用序列实现不可变和无副作用的编程,同时还提供惰性评估机制等。
  3. ReduxXState为不可变状态管理提供解决方案。

最后一个例子

最后重申你自己的例子


以上是当JavaScript没有提供任何明显的实现不变性的方法时,人们如何在JavaScript中实现不可变的数据结构?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>