Record и Tuple в JavaScript
Record
и tuple
— это новые примитивы (предложение второго этапа), которые по замыслу разработчиков должны быть очень похожи на объекты и массивы соответственно, но отличаться от них в одном важнейшем аспекте. Это глубокая иммутабельность.
Разумеется, иммутабельность подразумевает невозможность изменения его значения. Все, что можно сделать, — это создать копию.
Глубокая иммутабельность — это ещё более важный момент. Поскольку мы гарантируем, что все вложенные структуры иммутабельны, мы можем сравнивать глубоко вложенные структуры просто с помощью ===
так же, как мы сравниваем примитивы. Фактически, авторы предложения называют их новыми (составными) примитивами.
Глубоко иммутабельные примитивы позволили бы упростить код, но также позволили бы JS-движкам выполнять оптимизацию при построении, манипулировании и сравнении этих примитивов.
Как создать record
/tuple
Вот как создаётся record
(или tuple
):
const user = #{
id: 123,
name: "John Silver",
// это tuple!
likes: #['cats', 'dogs', 'hamsters']
}
Да, это просто object
/array
, но с добавлением #
.
Обратите внимание, что их нельзя смешивать с мутабельными значениями.
const users = #[
{ name: "John" }
]
//=> TypeError: Tuple may only contain primitive values
Как работать с record
/tuple
Записи и кортежи во многих случаях ведут себя как обычные объекты и массивы.
// доступ к свойствам
user.id //=> 123
user.likes[1] //=> "dogs"
// Работает Object.map
Object.map(#{ x: 1, y: 2 }) //=> ['x', 'y']
// Работает Spread
const newTuple = #[ ...oldTuple, 42 ]
// есть map и filter
users
.filter(u => u.name.startsWith("John"))
.map(u => u.id)
// Кортежи итерируются
for (const u of users) { console.log(u.name); }
// Они даже JSON.stringify
JSON.stringify(#{ a: #[1, 2, 3] }); // '{"a":[1,2,3]}'
// и т.д.
В целом, вы используете привычные API.
Кроме того, есть некоторые вещи, которые нельзя делать с записями и кортежами, поскольку они не мутируют.
cont user = #{name: "John"}
user.name = "Jane"
//=> TypeError: Cannot assign to read only property 'name'
// то же самое для кортежа
const tuple = #[1, 2, 3]
tuple[0] = 5
//=> TypeError: Cannot assign to read only property '0'
// мутирующие функции отсутствуют
tuple.push(4)
//=> TypeError: tuple.push is not a function
Сравнение
Поскольку записи и кортежи гарантированно неизменяемы, их можно (глубоко) сравнивать по значению.
const user1 = #{
id: 1,
имя: 'John',
likes: #['cats', 'dogs']
}
const user2 = #{
id: 2,
имя: 'John',
likes: #['cats', 'dogs']
}
// да, тот же самый пользователь
user1 === user2 // true
Обратите внимание на разительный контраст с обычными объектами/массивами, где их приходится сравнивать либо рекурсивно, либо с помощью странных хаков вроде преобразования в JSON.
Авторы дают достаточно хорошее резюме в тексте предложения.