迹忆客 专注技术分享

当前位置:主页 > 学无止境 > WEB前端 > JavaScript >

JavaScript 中的 Tuples 和 Records 是什么?

作者:迹忆客 最近更新:2023/01/08 浏览次数:

不变性是我们谈论函数式编程时经常出现的一个常用术语。 这是因为它是其核心原则之一。 当我们谈论不可变对象时,我们只是意味着一旦声明了一个变量,它的值就不能在以后进行更改。 例如:

const presents = ['🎁', '📦', '🎀', '💝', '🎄'];

// --- 可变解决方案 ---

// 我们略过 🎁
// presents 将等价于 ['📦', '🎀', '💝', '🎄'];
presents.shift();

// --- 不可变的解决方案 ---

// newPresents 相当于 📦 🎀 💝 🎄
// presents 依然为 ['🎁', '📦', '🎀', '💝', '🎄'];
const newPresents = presents.slice(1);

第一个解决方案改变了数组,而第二个解决方案创建了一个新的并保持原始数组不变。 在 JavaScript 中,我们没有真正的不可变对象,所以我们要么需要变通方法来实现安全,要么更糟糕的是,我们必须相信人们不会改变这些值。

现在有一个新的 ECMAScript 提案——目前处于第 2 阶段,因此这些实现可以改变——将引入两种新的不可变数据类型:Tuples和 Records。


Tuples(元组)

Tuples 和 Records 都具有相同的语法。 它们可以通过在对象和数组前面使用 # 前缀来定义,如下所示:

// 这是一个正常的数组
const arr = [];

// 这是一个 tuple
const tuple = #[];

使用 Tuples 时,需要注意一些规则:

  • 数组中不能有空洞,例如:[1, ,2] 是不允许的;
  • 它们只能包含原语或其他 Tuples 和 Records;
  • 支持类似于 Arrays 的实例方法,但有一些变化;

例如,改变数组的操作被替换为返回新数组的新操作。 因此,例如:没有 push,我们可以使用 push 来返回一个带有推送值的新元组,或者使用 with 来更改给定索引处的值:

const tuple = #['🍄', '🍅', '🥕'];

// 都返回一个新元组
tuple.pushed('🥒');  // 返回 #['🍄', '🍅', '🥕', '🥒'];
tuple.with(0, '🌳'); // 返回 #['🌳', '🍅', '🥕']

我们还可以使用 Tuple.from() 从现有数组创建元组:

Tuple.from(['🍄', '🍅', '🥕']);

// 同样,我们可以将元组转换为普通数组:
Array.from(tuple);

当然,它们是不可变的,如果尝试更改它们的值或使用非原始值,它们会抛出错误:

const tuples = #['🍄', '🍅', '🥕'];

// TypeError: Callback to Tuple.prototype.map may only return primitives, Records or Tuples
tuples.map(tuple => new Button(tuple));

Records 记录

就像元组一样,记录也用哈希表示:

// 这是一个常规对象
const obj = { ... };

// 这是一个记录
const record = #{
    tuple: #['🍄', '🍅', '🥕'] // Records 也会包含 元组(Tuples)
};

处理记录时,我们还需要牢记一些规则:

  • 不能在记录中使用 __proto__ 标识符
  • 方法也是不允许的。 就像元组一样,它们只能包含原语。

要创建新记录,我们还可以选择在使用元组时使用 RecordRecord.fromEntries

const record = Record({
    mushroom: '🍄',
    tomato: '🍅',
    carrot: '🥕'
});

// 或者
const record = Record.fromEntries(#['🍄', '🍅', '🥕']);

而且由于它们是新的数据类型,因此在使用 typeof 运算符时会返回“record”:

typeof #{ ... } // 返回 "record"
typeof #[ ... ] // 返回 "tuple"

总结

除了上面提到的示例之外,我们可以在函数或循环中同时使用记录和元组,就像我们通常使用常规对象一样。

如果你现在想要不可变,最简单的方法是使用 Immutable-js。 还可以使用 Object.freeze 实现部分不变性,但是,它只会冻结直接子级。 因此,我们仍然可以更改深度嵌套的属性:

const obj = Object.freeze({
    a: 1,
    b: {
        c: 2
    }
});

// ✅ Won't work
obj.a = 10;

// ❌ Will be changed to 20
obj.b.c = 20;

当然,你也可以通过 plugin-syntax-record-and-tuple 插件将它与 Babel 一起使用。

大家是否已经使用过元组(Tuples)和记录(Records)? 欢迎大家在下面留言一起来讨论!

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便