Object.prototype.constructor与Symbol.species的区别是什么?
Object.prototype.constructor 与 Symbol.species 的核心差异
默认场景下二者取值确实会保持一致,但二者的设计目标、作用逻辑完全不同,核心区别可以分为三类:
- 设计定位完全不同
constructor是实例的原型链属性,核心作用是标识「当前实例由哪个构造函数创建」,属于实例溯源的元数据,是从实例反查构造函数的入口。
Symbol.species是构造函数的静态知名符号属性,核心作用是声明「当前构造函数创建的实例,在生成派生对象时应该使用哪个构造函数作为构造器」,属于构造函数控制派生行为的配置项。 - 作用场景完全独立
我们可以通过自定义Array子类的例子直观看到差异:
从例子可以看到:constructor只负责标记当前实例的创建者,Symbol.species只负责控制派生新实例时使用的构造器,二者互不干扰。// 默认场景下二者取值一致 class MyArray extends Array {} const arr1 = new MyArray(1,2,3) console.log(arr1.constructor === MyArray) // true console.log(MyArray[Symbol.species] === MyArray) // true const mapped1 = arr1.map(i => i * 2) console.log(mapped1 instanceof MyArray) // true // 仅修改Symbol.species,不影响constructor的溯源能力 class MyArray2 extends Array { static get [Symbol.species]() { return Array } } const arr2 = new MyArray2(1,2,3) console.log(arr2.constructor === MyArray2) // 仍然为true,实例溯源不受影响 const mapped2 = arr2.map(i => i * 2) console.log(mapped2 instanceof MyArray2) // false console.log(mapped2 instanceof Array) // true - 修改影响范围完全不同
constructor是实例级别的属性,你可以单独修改某个实例的constructor属性,只会影响这一个实例的溯源结果,不会影响同构造函数创建的其他实例。
Symbol.species是构造函数的静态属性,一旦修改会影响所有该构造函数创建的实例的派生行为。
补充说明:ES6之后所有内置的派生类方法(比如数组的map/filter、Promise的then/catch)都会优先读取构造函数的Symbol.species作为派生实例的构造器,只有没有配置Symbol.species时才会 fallback 到实例的constructor。如果没有Symbol.species,想要调整派生实例的类型就只能修改constructor,会直接破坏实例溯源的逻辑,或者覆写所有会生成派生实例的方法,维护成本极高,Symbol.species就是为了解耦「实例溯源」和「派生规则配置」两个需求而生的。
内容的提问来源于stack exchange,提问作者user13892091
相关产品推荐
相关产品推荐

