JS工厂函数不支持原生继承,但可通过Object.setPrototypeOf建立原型委托、Object.assign复制方法或混合构造函数三种方式手动模拟继承。

JS 中工厂函数本身不直接支持继承机制,因为它返回的是普通对象,没有原型链绑定、无法用 instanceof 判断类型,也不自动关联构造器。但你可以**手动模拟继承行为**,让工厂函数创建的对象“看起来”具备父类属性和方法,甚至共享原型上的逻辑。关键不是靠 new 和 prototype 链式继承,而是通过属性复制或委托原型来实现功能复用。
用 Object.setPrototypeOf 建立原型委托关系
这是最贴近传统继承语义的做法:让工厂产出的对象的 __proto__ 指向某个“父类原型”,从而能访问其共享方法。
- 先定义一个“类原型”(比如
Animal.prototype),把通用方法放进去 - 工厂函数内部创建空对象后,立即用
Object.setPrototypeOf(obj, Animal.prototype)绑定 - 再添加实例专属属性(如
name、type)
示例:
const Animal = function() {};
Animal.prototype.speak = function() {
return `I'm ${this.name}`;
};
function createDog(name, breed) {
const obj = { name, breed };
Object.setPrototypeOf(obj, Animal.prototype); // 关键:手动挂原型
return obj;
}
const dog = createDog('Leo', 'Golden');
console.log(dog.speak()); // "I'm Leo"
console.log(dog instanceof Animal); // false(仍不是 Animal 实例,但可调用方法)
用 Object.assign 复制父类原型方法到实例
如果不想改原型链,也可以把父类原型上的方法一次性拷贝到新对象上,适合轻量、一次性对象。
- 适用于不需要动态更新方法、也不关心类型识别的场景
- 避免了原型污染风险,也绕过
instanceof限制 - 缺点是每个对象都有一份方法副本,内存开销略大
示例:
const AnimalMethods = {
speak() { return `I'm ${this.name}`; },
eat(food) { return `${this.name} eats ${food}`; }
};
function createCat(name, color) {
const obj = { name, color };
Object.assign(obj, AnimalMethods); // 浅拷贝方法
return obj;
}
const cat = createCat('Mimi', 'black');
console.log(cat.speak()); // "I'm Mimi"
组合工厂 + 构造函数做混合方案
若需类型识别、又想保留工厂的灵活性,可让工厂函数内部调用构造函数,再扩展定制逻辑。
- 先用
new ParentConstructor()创建基础实例 - 再在工厂中添加子类特有属性或覆盖方法
- 返回的对象既是
ParentConstructor实例,又带派生特征
示例:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return `Animal ${this.name} makes a sound`;
};
function createLion(name, pride) {
const lion = new Animal(name); // 继承 Animal 基础结构
lion.pride = pride;
lion.roar = function() { return `${this.name} ROARS!` };
return lion;
}
const simba = createLion('Simba', 'Pride Rock');
console.log(simba.speak()); // 来自 Animal.prototype
console.log(simba.roar()); // 子类独有
console.log(simba instanceof Animal); // true
注意:工厂函数不适合纯原型链继承
标准的原型链继承(如 Child.prototype = Object.create(Parent.prototype))依赖构造函数和 new,而工厂函数不参与该流程。强行在工厂里操作 Child.prototype 不起作用——因为返回的对象不通过 new Child() 创建,不会自动链接到那个原型。
- 不要在工厂函数里写
Child.prototype = ...,它对返回对象无效 - 不要期望
createXxx() instanceof Xxx返回true,除非你返回的是new Xxx()实例 - 若强依赖类型系统(如 TypeScript 类型推导、框架校验),建议优先用 class / 构造函数,而非工厂


















