导出构造函数是最标准做法,将方法挂到其prototype上并export default该构造函数,外部import后new实例即可调用共享方法;class语法是现代推荐写法,语义清晰且支持静态方法与tree-shaking。

JavaScript 原型链本身不直接“导出”方法,它是一种运行时对象间继承和查找的机制;真正实现跨模块共享方法,靠的是**把方法挂到构造函数的 prototype 上,再将该构造函数(或其原型)通过模块系统导出**。关键在于:导出的是“构造函数”,不是 prototype 对象本身;外部引入后,通过 new 或原型链自然获得共享能力。
导出构造函数,让 prototype 方法随之一同可用
这是最标准、最安全的做法。外部模块 import 构造函数后,即可创建实例并调用其 prototype 上的方法,无需额外操作:
- 在 utils.js 中定义构造函数,并在其 prototype 上添加方法
- 用 export default 或 export 导出该构造函数
- 在其他模块中 import 后,new 实例即可使用 sayHello 等共享方法
示例:
// utils.js
function Greeter(name) {
this.name = name;
}
Greeter.prototype.sayHello = function() {
return `Hello, ${this.name}`;
};
Greeter.prototype.greetAll = function(names) {
return names.map(n => `Hello, ${n}`);
};
export default Greeter; // ✅ 导出构造函数
// main.js
import Greeter from './utils.js';
const g = new Greeter('Alice');
console.log(g.sayHello()); // Hello, Alice
导出 prototype 对象(谨慎使用)
可以直接导出 Greeter.prototype,但需注意:外部无法直接 new,只能手动 assign 到已有对象或 Object.setPrototypeOf。适用场景少,一般只用于工具类扩展或 patch 行为:
- 适合向已有对象(如自定义类实例)动态注入一组方法
- 不适用于常规实例化流程,易造成原型链混乱
- 导出时建议重命名,避免误用
// utils.js
export const GreeterMethods = {
sayHello() { return `Hello, ${this.name}`; },
farewell() { return `Goodbye, ${this.name}`; }
};
// 或导出原型引用(不推荐默认方式)
export const greeterProto = Greeter.prototype;
配合 class 语法 + 默认导出(现代推荐写法)
class 本质仍是基于 prototype 的语法糖,导出 class 即等价于导出构造函数,语义更清晰,且天然支持静态方法与实例方法分离:
- 所有实例方法自动挂载到 prototype
- 可同时导出静态辅助方法(不依赖 this)
- 支持 tree-shaking,模块系统识别更友好
// Greeter.js
export default class Greeter {
constructor(name) {
this.name = name;
}
sayHello() {
return `Hello, ${this.name}`;
}
static createBatch(names) {
return names.map(n => new Greeter(n));
}
}
// app.js
import Greeter from './Greeter.js';
const a = new Greeter('Tom');
a.sayHello(); // ✅ 正常调用 prototype 方法
不推荐的误区
以下做法会破坏共享性或导致不可预期行为:
- 导出实例本身:如 export const instance = new Greeter('X') —— 外部拿到的是单个对象,无法复用原型链机制
- 直接导出绑定 this 的方法:如 export const sayHello = (name) => ... —— 脱离了原型上下文,失去 this 绑定和继承意义
- 在 prototype 上设置可变引用类型属性(如数组、对象):多个实例会共享同一份数据,引发状态污染











