MST
星途 面试题库

面试题:TypeScript中readonly数组与普通数组的差异及应用场景

请详细阐述TypeScript中readonly数组与普通数组在类型定义、使用方法及内存层面的差异,并举例说明readonly数组在实际项目中的应用场景,以及如何通过readonly避免值变错误。
36.8万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

类型定义差异

  • 普通数组:在TypeScript中,普通数组类型定义可以使用 类型[] 或者 Array<类型> 的形式。例如:let arr: number[] = [1, 2, 3]; 或者 let arr: Array<number> = [1, 2, 3];,这样定义的数组可以自由修改其元素值。
  • readonly数组:readonly数组使用 readonly 类型[] 的形式定义。例如:let readonlyArr: readonly number[] = [1, 2, 3];,这种数组一旦初始化,其元素值不能被修改。

使用方法差异

  • 普通数组:普通数组具有可变性,支持多种修改操作,如通过索引修改元素值、使用 pushpopsplice 等方法改变数组结构。例如:
let arr: number[] = [1, 2, 3];
arr[0] = 4;
arr.push(5);
  • readonly数组:readonly数组是只读的,不能通过索引直接修改元素值,也不支持 pushpopsplice 等会改变数组结构的方法。尝试修改会导致编译错误。例如:
let readonlyArr: readonly number[] = [1, 2, 3];
// readonlyArr[0] = 4; // 报错:无法分配到 "0" ,因为它是只读属性。
// readonlyArr.push(4); // 报错:类型“readonly number[]”上不存在属性“push”。

内存层面差异

在内存层面,普通数组和readonly数组在存储结构上可能并无本质区别,主要差异体现在对内存数据的可写权限上。普通数组允许对内存中存储的元素值进行修改,而readonly数组在编译层面限制了对其内存数据的修改操作,保证了数据的不可变性,这有助于提升程序的稳定性和可维护性。

实际项目应用场景

  1. 配置数据:在项目中,一些配置数据通常不应该被修改,使用readonly数组可以确保配置的稳定性。例如,一个包含一周中固定日期名称的数组:
const weekDays: readonly string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
// 在后续代码中,weekDays不会被意外修改,保证了数据的一致性。
  1. API返回的不可变数据:当从API获取到一些不应该被修改的数据时,将其定义为readonly数组可以防止程序内部意外修改。例如,获取某个固定的选项列表:
async function getOptions(): Promise<readonly string[]> {
    // 模拟API请求
    return ['Option1', 'Option2', 'Option3'];
}
const options = await getOptions();
// 防止在后续代码中意外修改options

通过readonly避免值变错误

假设在一个复杂的项目中,有一个数组用于存储一些关键的初始化参数,这些参数在整个应用生命周期中不应被修改。如果使用普通数组,可能会在代码的某个角落因为疏忽而修改了这些参数,导致难以排查的错误。例如:

// 错误示例,使用普通数组
let criticalParams: number[] = [100, 200, 300];
// 其他开发人员在不知情的情况下可能会意外修改
function someFunction() {
    criticalParams[0] = 500;
}
someFunction();
// 这可能会导致依赖这些初始参数的功能出现异常

// 正确示例,使用readonly数组
let readonlyCriticalParams: readonly number[] = [100, 200, 300];
// 尝试修改会在编译阶段报错,提前发现问题
function someFunction() {
    // readonlyCriticalParams[0] = 500; // 编译错误,避免值变错误
}
someFunction();

通过将数组定义为readonly,可以在编译阶段捕获对数组值的意外修改,避免在运行时出现难以调试的值变错误,提高代码的健壮性。