Javascript 记录Records和元组Tuples

Records and Tuples 是 Javascript 即将推出的功能,如果您使用过其他语言,可能会很熟悉。它们与 and 非常相似ArraysObjects主要区别在于它们是不可变的,这意味着它们无法更新或更改。它们在 Javascript 中为我们提供了一种全新的原始类型,让我们可以做很多以前无法做到的事情,包括通过值而不是身份来比较对象和数组。在本文中,我们将介绍它们的工作原理以及您现在如何使用它们。

支持记录和元组#

目前,记录和元组是 Javascript 的第 2 阶段提案。从广义上讲,这意味着它们相对稳定,但没有作为标准规范实施。因此,主流浏览器和 Node.JS 等后端 Javascript 并没有实现它们。但是,如果你有 Babel,你可以通过使用这个 polyfill 来使用它们。

Javascript 中的记录和元组是什么?#

Records 和Tuples 为 Javascript 引入了一种全新的原始类型,但最终遵循与Objects 和Arrays 相同的语法。当我们想要定义一个新的RecordorTuple时,我们使用语法#{}or #[]。因此,我们可以定义两者,如下面的代码所示:

let myRecord = #{
    name: "New Record",
    tags: #['some', 'tags', 'go', 'here']
}

let myTuple = #['some', 'other', 'set', 'of', 'array', 'items'];

如您所见,语法对象和数组相同,#但开头的哈希 ( ) 除外。请注意,我们也可以将 aTuple放入我们的 中Record,如第一个示例所示。

记录和元组是不可变的#

Javascript 中的记录和元组都是不可变的。这意味着它们在任何级别都无法更改。如果您尝试更改它们,则会收到错误消息:

let myRecord = #{
    name: "New Record",
    tags: #['some', 'tags', 'go', 'here']
}

myRecord.name = 'Another Record'; // This will throw an error

这也意味着你不能在其中插入新的东西。通过这种方式,它们充当了事实的来源——这将我们带到了它们的主要用例中。Tuples 和s都Record允许我们根据它们的值而不是它们的身份来比较对象和数组。

记录和元组比较值,而不是身份#

如果您尝试运行以下代码,您将false返回:

console.log({ a: 1 } === { a: 1 }) // returns false
console.log([1, 2, 3] === [1, 2, 3]) // returns false

这可能会让人感到困惑,但这是因为对象和数组的相等性是在身份的基础上工作的。当我们定义一个新的对象或数组时,它被赋予了一个唯一的身份。因此,当比较两个不同对象的身份时,结果是false

记录和元组打破了这个约定,让我们可以按值进行比较。Deep comparisons很长一段时间以来,对象的数量一直是 Javascript 中相当棘手的事情,但有了元组和记录,我们终于可以做到这一点。因此,以下代码返回 true:

console.log(#{ a: { b : 3 }} === #{ a: { b : 3 }}) // return true
console.log(#[1, 2, 3] === #[1, 2, 3]) // returns true

这意味着我们最终可以(并且很容易地)比较不同对象之间的值,我们期望一个非常具体的返回值。

在 Javascript 中将数组转换为元组和将对象​​转换为记录#

由于 Records 和 Tuples 是按值比较的,因此您可能希望将常规 Objects 和 Arrays 转换为它们,以便进行比较。幸运的是,我们可以使用Record()and将任何对象或数组转换为记录或元组Tuple()

let newRecord = Record({ a: 1, b: 2 });
let newTuple = Tuple(...[1, 2, 3, 4, 5]);
let anotherTuple = Tuple.from([1, 2, 3, 4, 5]);

上述两行都将生成每个的 Record 和 Tuple 版本。未来的提议还包括一个JSON.parseImmutable函数,它可以让我们将数组或对象的字符串直接转换为它们的元组或记录形式。目前尚未实施。

添加到元组或记录#

我知道我刚刚说过您不能添加或更改元组/记录 – 但您可以根据旧的元组或记录生成新的元组或记录。这将是一个完全不同的元组/记录——但它将使用旧的数据并添加一些新的东西。我们可以这样做,如下所示:

let myTuple = #[1, 2, 3, 4, 5];
let myRecord = #{ a: 1, b: 1 };

// Produce a new record using original myRecord:
let newRecord = #{ ...myRecord, c: 1 } // #{ a: 1, b: 1, c: 1}
// Produce a new tuple using myTuple:
let newTuple = #[ ...myTuple, 6, 7];
// Or you can use Tuple.with():
let anotherTuple = myTuple.with(6, 7);

在 Javascript 中与元组和记录交互#

元组和记录的工作方式与对象和数组完全相同,只是它们不能更改。因此,您可以遍历它们,或者使用与对象和数组相同的方法与它们交互。例如,我们可以获取特定 Record 的所有键:

let myRecord = #{ a: 1, b: 2, c: 2};
let recordKeys = Object.keys(myRecord); // Returns ['a', 'b', 'c'];

或者您可以使用 for 循环遍历数组:

let myTuple = #[1, 2, 3, 4, 5];
for(const i of myTuple) {
    console.log(i);
}

// Console logs 1, 2, 3, 4, 5 on after each other

结论#

由于Tuples 和Records 没有得到广泛支持,你需要 Babel polyfill 才能使用它们。它们使我们能够以前所未有的方式比较来自对象和数组的数据,从而使曾经需要复杂自定义函数的代码变得更加简单。要阅读完整的提案,请单击此处