Tuple 类型
Tuple 类型目前处于 stage-2 阶段
Tuple 类型是一种类数组的结构,具有深度不可变的特点,即每个元素都是只读的,不能直接修改,对 tuple 的操作都会返回一个新的 tuple 实例。
在前端状态管理中,需要保证状态对象或数组是不可变的,否则会导致视图不刷新等异常情况,这是因为 JavaScript 对象是引用类型,保存的是对象的内存地址,如果修改了对象的内容,它的内存地址不会发生变化,这时如果在前端状态中,使用 ===
判断,这里的的对象还是原来的,就不能探测到状态的变化,也就不能更新对应的视图了:
const state = {
arr: [1, 2, 3]
};
state.arr[0] = 4; // 并没返回新的数组
// 正确做法是:
state.arr = [4, ...arr.slice(1)]
前端库中,一般使用 immer.js 来实现不可变的数据,也有的库自行封装了一些逻辑,检测数组或对象的赋值操作,并返回全新的对象/数组。
Tuple 类型的出现就可以让我们避免使用第三方库,或者自行维护实现不可变数据的代码了。
使用 Tuple 类型
因为 Tuple 类型还处于 stage-2 阶段,所以我们还需要 babel 来体验。使用上一节配置好的 babel 项目,我们先安装 @babel/plugin-proposal-record-and-tuple
和 @bloomberg/record-tuple-polyfill
依赖,分别是 babel对 Tuple 进行转译的插件和执行代码所必须的补充库:
yarn add --dev @babel/plugin-proposal-record-and-tuple @bloomberg/record-tuple-polyfill
之后,打开 babel.config.json
,在 plugins 配置项中添加如下内容:
"plugins": [["@babel/plugin-proposal-record-and-tuple", {"syntaxType": "hash", "importPolyfill": true}]]
这里:
- 我们添加了
@babel/plugin-proposal-record-and-tuple
插件。 - 配置了
syntaxType
,它是 Tuple 类型数据的语法类型,hash 表示使用 "#",它还可以取值 "bar"。 importPolyfill
会自动导入我们之前安装的@bloomberg/record-tuple-polyfill
,用于运行编译后的代码。
我们还可以在 package.json
里添加一个 start
命令,来运行编译后的代码:
"scripts": {
"build": "babel index.js -o dist.js",
"start": "node dist.js"
},
示例
首先,看一下如何定义 Tuple 型数据。Tuple 类型的数据以 #
开头,后面的语法和数组一样,在 index.js 中,定义一个包含 1、2、3、4 这 4 个元素的 Tuple,之后 log 一下它的值:
const tuple = #[1, 2, 3, 4];
console.log(tuple);
运行 yarn build
,转译代码,之后运行 yarn start
运行,可以看到命令行中打印出来了结果:
Tuple { '0': 1, '1': 2, '2': 3, '3': 4 }
这里 Tuple 类型就是 @bloomberg/record-tuple-polyfill
提供的目前 ECMAScript 语法可以兼容的版本,可以看到它使用了一个类数组的对象来表示 Tuple,当 Tuple 类型正式加入 ECMAScript 之后,会有专门的表示方法。
访问 Tuple 中的元素,和访问数组中的一样:
console.log(tuple[0]); // 1
因为 Tuple 是不可变的类型,所以不能直接修改它里边元素的值,例如下面这行代码会报错:
// TypeError: Cannot assign to read only property '0' of object '[object Tuple]'
tuple[0] = 5;
如果要修改 Tuple 元素的值,可以使用 with() 方法,例如把第 1 个元素的值改成 5,之后再把返回的结果保存到 newTuple 变量中,我们看看它和我们之前定义的 tuple 变量是不是指向了相同的内容地址:
const newTuple = tuple.with(0, 5);
console.log(newTuple, newTuple === tuple);
输出结果为:
Tuple { '0': 5, '1': 2, '2': 3, '3': 4 } false
可以看到成功的修改了第 1 个元素的值,并且返回的新 Tuple 和之前的也是不同的。
Tuple 类型也封装了和数组一样的方法,例如可以使用 map() 遍历所有 tuple 元素,并返回一个新的 Tuple:
// Tuple { '0': 2, '1': 4, '2': 6, '3': 8 }
console.log(tuple.map((x) => x * 2));
也可以使用针对数组的一些运算符,例如 spread:
const newTuple2 = #[...tuple, 5];
// Tuple { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }
console.log(newTuple2);
或者解构赋值:
const [a, b] = tuple;
console.log(a, b); // 1, 2
需要注意的是,Tuple 类型里边只能包含基本类型数据,或者其他 Tuple 类型的数据,或者下节要介绍的 Record 数据,否则会破坏不可变特性,程序也会报错,例如下面的代码试图把一个普通的数组放到 Tuple 类型中,这是不可以的:
const newTuple2 = #[...tuple, 5, [6, 7]]; // 错误
一系列的课程让你成为高级前端工程师。课程覆盖工作中所有常用的知识点和背后的使用逻辑,示例全部都为工作项目简化而来,学完即可直接上手开发!
即使你已经是高级前端工程师,在课程里也可能会发现新的知识点和技巧,让你的工作更加轻松!
《React 完全指南》课程,包含 React、React Router 和 Redux 详细介绍,所有示例改编自真实工作代码。点击查看详情。
《Vue 3.x 全家桶完全指南与实战》课程,包括 Vue 3.x、TypeScript、Vue Router 4.x、Vuex 4.x 所有初级到高级的语法特性详解,让你完全胜任 Vue 前端开发的工作。点击查看详情。
《React即时通信UI实战》课程,利用 Storybook、Styled-components、React-Spring 打造属于自己的组件库。
《JavaScript 基础语法详解》本人所著图书,包含 JavaScript 全面的语法知识和新特性, 可在京东、当当、淘宝等各大电商购买