MST

星途 面试题库

面试题:TypeScript类的实例方法与实例属性在复杂场景下的性能优化及设计考量

在一个大型前端项目中,有一个频繁创建实例的类`DataProcessor`。该类有多个实例属性用于存储中间计算结果,同时有多个实例方法用于处理数据。为了优化性能,你会如何在实例属性的存储方式(例如使用WeakMap等)和实例方法的设计(如函数柯里化、防抖节流等)上进行考量,以减少内存占用和提高执行效率?请结合TypeScript的类型系统详细说明设计思路和具体实现。
27.2万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

实例属性存储方式考量

  1. 使用WeakMap
    • 设计思路
      • 在大型前端项目中,DataProcessor频繁创建实例,如果使用普通对象存储实例属性,当实例不再被使用时,由于属性对实例的强引用,实例无法被垃圾回收,可能导致内存泄漏。而WeakMap的键是弱引用,当键(即实例)不再有其他强引用时,垃圾回收机制可以回收该实例及其占用的内存,从而减少内存占用。
    • 具体实现(TypeScript)
const instanceProperties = new WeakMap<DataProcessor, { [key: string]: any }>();
class DataProcessor {
    constructor() {
        instanceProperties.set(this, {});
    }
    getProperty(key: string) {
        return instanceProperties.get(this)?.[key];
    }
    setProperty(key: string, value: any) {
        const props = instanceProperties.get(this);
        if (props) {
            props[key] = value;
        }
    }
}
  1. 其他考量
    • 静态属性替代部分实例属性:如果某些属性在所有实例中是相同的,可以将其定义为静态属性。例如,如果有一个全局配置项,可以作为DataProcessor类的静态属性,而不是每个实例都有一份拷贝。
class DataProcessor {
    static globalConfig: { [key: string]: any } = { someSetting: 'defaultValue' };
    constructor() {}
}

实例方法设计考量

  1. 函数柯里化
    • 设计思路
      • DataProcessor的实例方法有多个参数,且某些参数在多次调用中保持不变时,使用函数柯里化可以将部分参数提前绑定,返回一个新的函数,这样在后续调用时只需传入变化的参数,减少每次调用时重复传递相同参数的开销,提高执行效率。
    • 具体实现(TypeScript)
class DataProcessor {
    // 假设一个处理数据的方法
    processData(baseValue: number, multiplier: number, adder: number): number {
        return (baseValue * multiplier) + adder;
    }
    curriedProcessData(baseValue: number) {
        return (multiplier: number) => (adder: number) => {
            return this.processData(baseValue, multiplier, adder);
        };
    }
}
const dp = new DataProcessor();
const curriedFunc = dp.curriedProcessData(10);
const result1 = curriedFunc(2)(5); // 结果为25
  1. 防抖节流
    • 设计思路
      • 如果DataProcessor的实例方法是频繁触发的,比如可能是一个根据用户输入实时处理数据的方法,使用防抖或节流可以控制方法的执行频率。防抖是在一定时间内多次触发只执行一次,适合像搜索框输入实时搜索的场景,减少不必要的计算;节流是在一定时间间隔内只执行一次,适合像滚动事件实时处理数据的场景,防止短时间内大量计算。
    • 具体实现(TypeScript,以防抖为例)
function debounce<T extends (...args: any[]) => void>(func: T, delay: number): T {
    let timer: NodeJS.Timeout | null = null;
    return ((...args: any[]) => {
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            func.apply(this, args);
            timer = null;
        }, delay);
    }) as T;
}
class DataProcessor {
    realTimeProcessData(data: string) {
        // 实际处理数据逻辑
        console.log(`Processing data: ${data}`);
    }
    debouncedProcessData = debounce(this.realTimeProcessData.bind(this), 300);
}
const dp2 = new DataProcessor();
dp2.debouncedProcessData('input1');
dp2.debouncedProcessData('input2'); // 在300ms内多次调用,只会实际执行一次realTimeProcessData