继承Array重写filter方法异常:构造函数被传入[0]
继承Array时filter方法触发构造函数传入[0]的根本原因及解决办法
根本原因
内置Array.prototype.filter方法在生成结果数组时,会使用原数组的构造函数来创建新实例。当你调用Array.prototype.filter.call(this, predicate)时,this是MyArray的实例,所以filter内部会调用new MyArray(0)——这里的0是filter用来初始化新数组长度的默认参数。
你的MyArray构造函数对单参数的处理逻辑完全违背了内置Array的设计:内置Array在传入单个数字时是指定数组长度(比如new Array(3)生成长度为3的空数组),但你却把这个长度参数当成了元素,重置length为0后再push进去,导致原本应该是空数组的结果变成了[0]。
执行流程拆解
- 调用
myArray.filter(num => num === "nonsense")时,filter遍历原数组后发现没有符合条件的元素,需要创建一个长度为0的新数组。 - 由于
myArray是MyArray实例,filter会调用new MyArray(0)来生成结果。 - 你的构造函数检测到
nums.length === 1,执行this.length = 0并push传入的0,最终得到[0]而非预期的空数组。 [...this].filter(predicate)能解决问题,是因为[...this]把MyArray实例转成了普通Array,filter返回的是普通空数组,不会触发MyArray的构造函数,但会产生额外的数组拷贝。
无拷贝的正确解决方式
要让filter返回正确的MyArray实例,需要让构造函数兼容内置Array的两种调用逻辑:单个数字参数表示数组长度,多个参数表示初始化元素。修改后的代码如下:
class MyArray extends Array { constructor(...nums) { // 兼容内置Array的两种构造逻辑 if (nums.length === 1 && typeof nums[0] === 'number') { super(nums[0]); } else { super(...nums); } this.tmpStore = {}; // 保留你的自定义属性 } filter(predicate) { // 直接调用super.filter即可,内置逻辑会正确创建MyArray实例 return super.filter(predicate); } }
修改后,当filter调用new MyArray(0)时,构造函数会按长度初始化出空数组,完全符合预期,且没有额外的数组拷贝开销。
内容的提问来源于stack exchange,提问作者crazyones110
相关产品推荐
相关产品推荐

