继承Array的自定义类调用splice触发map函数报错问题排查
问题原因分析
这个错误的核心是你自定义的PositionsAndMedia构造函数的参数设计,和Array内置方法调用构造函数的方式不匹配。
你的构造函数预期接收一个数组作为唯一参数,但当你调用splice、slice这类Array内置方法时,这些方法在生成返回的新数组实例时,会调用你的PositionsAndMedia构造函数,并且将新数组的元素作为单独的参数逐个传递,而不是把元素包装成一个数组传递。
举个具体的例子:假设splice删除了1个元素,它会执行new PositionsAndMedia(被删除的那个元素),此时构造函数里的x就是这个单个元素(不是数组),自然调用x.map()就会抛出“不是函数”的错误。
解决方法
有两种实用的解决方案,你可以根据业务需求选择:
方案1:让构造函数兼容可变参数
修改构造函数,使其既能处理用户传入的单个数组参数,也能处理Array方法传入的多个元素参数:
class PositionsAndMedia extends Array { constructor(...args) { // 统一处理输入:如果是单个数组参数,就用数组内容;否则直接用传入的所有参数 const inputItems = args.length === 1 && Array.isArray(args[0]) ? args[0] : args; // 避免重复创建MyClass实例:如果已经是MyClass实例,直接保留 super(...inputItems.map(item => item instanceof MyClass ? item : new MyClass(item))); } }
这种方式的好处是,所有Array内置方法返回的仍然是PositionsAndMedia实例,且内部元素保持MyClass类型,完全符合你的自定义类设计。
方案2:指定Array方法返回普通Array
如果你不需要内置方法返回自定义类实例,可以重写类的Symbol.species属性,让Array方法生成普通的Array实例:
class PositionsAndMedia extends Array { constructor(x) { super(...x.map(item => new MyClass(item))); } // 告诉Array内置方法:用Array作为构造函数创建返回值 static get [Symbol.species]() { return Array; } }
这样调用splice时,返回的就是普通Array,不会触发你的自定义构造函数,也就不会出现错误。但要注意,这种方式下所有Array方法的返回值都不再是PositionsAndMedia类型,需要根据你的业务场景判断是否适用。
内容的提问来源于stack exchange,提问作者Paolo Benvenuto
相关产品推荐
相关产品推荐

