了解TC39 的 Record-Tuple 提案
摘要:最近看某人的文章《JavaScript新增两个数据类型》,就特地多看了几眼,发现削微有点标题党了。
前言
最近看某人写文章说JavaScript新增两个数据类型,就特地多看了几眼,发现削微有点标题党了,关于 Record 和 Tuple这两个数据类型其实是TC39在2019年提出的一项提案,2020年走到Stage2阶段后就一直没变化,距离被ECMAScript接纳的Stage4阶段还有一些时间,大家不用慌,先了解一下即可;
使用说明
Record
使用#作为对象声明的修饰符,即表明该变量为Record数据类型,具备对象的基本操作方法
const r = #{
a:100,
b:200
}
console.log(r.a); // 100
console.log(Object.keys(r)); // ["a","b"]
r.a = 300; // Cannot assign to read only property 'a' of object '[object Object]'
Tuple
使用#作为数组声明的修饰符,即表明该变量为Tuple数据类型, 具备数组的基本操作方法
const t=#[1,2,3];
console.log(t[0]); // 1
console.log(t.length); //3
t[0] = 1; // Cannot assign to read only property '0' of object '[object Tuple]'
结论
Record和Tuple这俩是干啥的一句话就能整明白:前者是只读的Object,后者是只读的Array;
它们的共同点是不可变,而且成员只能由值类型以及同样不可变的Record和Tuple组成。
// 正确的声明
const r1 = #{
a: 100,
t: #[1,2,3]
}
const t1 = #[r1,2,3]
// TypeError: cannot use an object as a value in a record
const rr = #{
ob: {a:100}
}
// TypeError: cannot use an object as a value in a record
const tt = #[[1,2,3]]
根据上述特性,我们可以得知 Record和Tuple可以按值比较:
const r1 = #{a:100}
const r2 = #{a:100}
console.log(r1 === r2) // true
const t1 = #[1,2,3]
const t2 = #[1,2,3]
console.log(t1 === t2) //true
关于这个提案的前因后果、发展过程,在该提案的gayhub Readme中也给出了解释,英语优秀的同学可以在评论中帮忙翻译一下
Today, userland libraries implement similar concepts, such as Immutable.js. Also a previous proposal has been attempted but abandoned because of the complexity of the proposal and lack of sufficient use cases.
This new proposal is still inspired by this previous proposal but introduces some significant changes: Record and Tuples are now deeply immutable. This property is fundamentally based on the observation that, in large projects, the risk of mixing immutable and mutable data structures grows as the amount of data being stored and passed around grows as well so you'll be more likely handling large record & tuple structures. This can introduce hard-to-find bugs.
As a built-in, deeply immutable data structure, this proposal also offers a few usability advantages compared to userland libraries:
- Records and Tuples are easily introspectable in a debugger, while library provided immutable types are often hard to inspect as you have to inspect through data structure details.
- Because they're accessed through typical object and array idioms, no additional branching is needed in order to write a generic library that consumes both immutable and JS objects; with user libraries, method calls may be needed just in the immutable case.
- We avoid cases where developers may expensively convert between regular JS objects and immutable structures, by making it easier to just always use the immutable ones.
Immer is a notable approach to immutable data structures, and prescribes a pattern for manipulation through producers and reducers. It is not providing immutable data types however, as it generates frozen objects. This same pattern can be adapted to the structures defined in this proposal in addition to frozen objects.
Deep equality as defined in user libraries can vary significantly, in part due to possible references to mutable objects. By drawing a hard line about only deeply containing primitives, Records and Tuples, and recursing through the entire structure, this proposal defines simple, unified semantics for comparisons.