Symbol.species 是用于指定派生对象创建时使用的构造器,影响 slice、map、then 等返回新实例的内置方法;需通过 static get [Symbol.species]() { return this; } 正确定义。

Symbol.species 是一个内置的符号值,用于指定创建派生对象时应使用的构造器。它主要影响内置方法(如 Array.prototype.slice、Array.prototype.map、Promise.prototype.then 等)在返回新实例时,**不直接使用当前类的构造器,而是优先使用 [Symbol.species] 指向的构造器**。这在自定义派生类时非常关键——否则像 slice() 这样的方法默认会返回父类(如 Array)实例,而非你的子类实例。
为什么需要 Symbol.species?
当你继承 Array 并重写 slice 行为时,若不干预,原生 slice 内部仍会调用 this.constructor 创建新数组。而子类实例的 this.constructor 就是子类本身——看似没问题。但问题在于:某些内置方法(尤其是涉及“派生新实例”的操作)会显式读取 this.constructor[Symbol.species],并用其结果代替 this.constructor 来构造返回值。
例如:Array 的 [Symbol.species] 默认是 Array 自身,所以 MyArray.prototype.slice 若未重定义,内部仍可能用 Array 构造器生成结果,导致返回普通 Array 而非 MyArray 实例。
如何正确设置 Symbol.species
在派生类中,通过静态 getter 定义 [Symbol.species],返回期望用于创建新实例的构造器:
- 返回
self(即类自身),可确保slice、map等方法返回该子类实例 - 返回
null或undefined,则回退到this.constructor - 返回其他构造器(如
Array),则强制返回对应类型实例
示例:
class MyArray extends Array {
static get [Symbol.species]() {
return this; // ✅ 返回当前类(支持子类链)
}
}
const arr = new MyArray(1, 2, 3);
const sliced = arr.slice(1); // 返回 MyArray 实例,而非 Array
console.log(sliced instanceof MyArray); // true
console.log(sliced instanceof Array); // true(因为继承自 Array)
哪些方法受 Symbol.species 影响?
并非所有方法都遵循此规则。主要影响以下内置方法:
-
Array.prototype.map、filter、slice、concat、flat -
TypedArray.prototype.map、filter、slice -
Promise.prototype.then、catch、finally -
RegExp.prototype.exec(仅当使用 sticky / global 标志且匹配成功时,用于构造结果数组)
注意:Array.prototype.push、pop、sort 等**不创建新实例**的方法不受影响;Array.from 和 Array.of 也不使用 species,它们只依赖传入的 constructor 参数或默认 Array。
常见陷阱与注意事项
-
必须是静态 getter:不能是属性赋值或实例属性,必须通过
static get [Symbol.species]()定义 -
箭头函数不可用:因需访问
this(指向当前类),不能写成static [Symbol.species] = () => this -
子类继承自动生效:若基类已定义
[Symbol.species]返回this,子类无需重复定义,除非要覆盖行为 -
Promise 的特殊性:
Promise.resolve(x)不走 species;只有then/catch/finally返回的新 Promise 才使用constructor[Symbol.species]

















