symbol.species 是用于指定内置方法创建新实例时使用的构造器,默认 array 子类的 symbol.species 指向 array,导致 map/filter 返回原生 array;需通过 static get [symbol.species]() { return this; } 显式设置为子类自身才能返回子类实例。

Symbol.species 是什么,为什么它会影响子类的返回类型
当你调用 Array.prototype.map、Array.prototype.filter 这类会返回新实例的方法时,JavaScript 引擎不会无脑返回当前构造器(比如子类 MyArray),而是查 constructor[Symbol.species] —— 如果这个属性存在且是函数,就用它来新建实例;否则才 fallback 到 constructor。这是为了保证方法链式调用后类型不“意外降级”或“意外升级”。
常见错误现象:class MyArray extends Array {}; const a = new MyArray(1,2); a.map(x => x * 2) 返回的是原生 Array,不是 MyArray 实例 —— 因为默认 MyArray[Symbol.species] 是 Array,不是 MyArray 自身。
如何显式设置 Symbol.species 让 map/filter 返回子类实例
在子类中静态定义 get [Symbol.species](),返回期望的构造器:
class MyArray extends Array {
static get [Symbol.species]() {
return MyArray;
}
}
这样 new MyArray(1,2).map(x => x + 1) 就返回 MyArray 实例,而不是 Array。
- 必须是 getter,不能是普通属性或方法;否则引擎忽略
- 返回值必须是可构造函数(
typeof === 'function'且有[[Construct]]),否则运行时报TypeError: species constructor is not a function - 如果返回
null或undefined,引擎会 fallback 到this.constructor(注意:不是Array)
Symbol.species 在哪些内置方法中生效
只影响明确使用 speciesConstructor 算法的内置方法,包括:
-
Array.prototype.map、filter、slice、concat、flat、flatMap -
TypedArray.prototype.map、filter等(但 TypedArray 子类不能自定义species,因为其[Symbol.species]固定为自身构造器) -
Promise.prototype.then、catch(返回新Promise时也走species)
不生效的场景:Array.prototype.push、pop、splice(它们修改原数组,不创建新实例);JSON.stringify、for...of(不涉及构造器选择)。
容易被忽略的兼容性与陷阱
Symbol.species 在 Node.js 6+、Chrome 51+、Firefox 49+ 支持,但 IE 完全不支持 —— 如果需兼容,不能依赖它做关键逻辑。
- 子类若继承自非内置类(如
class Foo extends EventEmitter),Symbol.species不起作用,因为EventEmitter的方法没实现speciesConstructor查找逻辑 - 如果子类重写了
map方法但没手动调用speciesConstructor,那自定义方法里就不会受Symbol.species影响 - V8 中,
Array.from和Array.of不走Symbol.species,它们始终用当前this.constructor
真正要靠它控制返回类型的,只有那些规范明确定义了 GetSpeciesConstructor 步骤的方法 —— 别想当然地以为所有“返回新数组”的操作都走这里。










