游乐游手机版
首页/前端开发/文章详情

详细对比解析SeaJS中exports与module.exports两种导出方式的区别实例

时间:2026-06-10 06:58
在 Sea js 模块化开发中,exports 与 module exports 这两个接口暴露方式,常常让刚接触模块加载的开发者感到困惑。表面上它们都用于对外提供模块功能,但一旦用错,模块将无法正确导出任何内容。下面通过几个具体实例,系统梳理它们的区别、正确用法以及常见陷阱。 关于这两者的关系,S

在 Sea.js 模块化开发中,exportsmodule.exports 这两个接口暴露方式,常常让刚接触模块加载的开发者感到困惑。表面上它们都用于对外提供模块功能,但一旦用错,模块将无法正确导出任何内容。下面通过几个具体实例,系统梳理它们的区别、正确用法以及常见陷阱。

seaJs使用心得之exports与module.exports的区别实例分析

关于这两者的关系,Sea.js 官方 issue #242(https://github.com/seajs/seajs/issues/242)中有详细讨论。简单归纳两点核心要点:

  • exportsmodule.exports 的辅助引用对象。如果只用 exports 暴露接口,需要理解它的本质——它只是一个指向 module.exports 的引用。
  • module.exports 可以直接作为模块的真实接口使用,适用场景更加灵活。

exports 对象详解

exports 本身是一个对象,常用于向外提供模块接口。最常见的做法是给它的属性逐一赋值:

define(function(require, exports) {
  // 对外暴露 foo 属性
  exports.foo = 'bar';
  // 对外暴露 doSomething 方法
  exports.doSomething = function() {};
});

除了通过 exports 添加成员,还可以直接用 return 返回接口对象:

define(function(require) {
  // 通过 return 直接返回接口
  return {
    foo: 'bar',
    doSomething: function() {}
  };
});

如果整个模块只有一个 return 语句,还可以进一步简化为直接传入对象字面量:

define({
  foo: 'bar',
  doSomething: function() {}
});

这种写法特别适合定义 JSONP 模块,既简洁又清晰。

⚠️ 特别注意:下面这种写法是错误的!

define(function(require, exports) {
  // 错误用法!!!千万不要这样写
  exports = {
    foo: 'bar',
    doSomething: function() {}
  };
});

正确的做法应该是使用 return 或者直接给 module.exports 赋值:

define(function(require, exports, module) {
  // 正确的写法
  module.exports = {
    foo: 'bar',
    doSomething: function() {}
  };
});

❓ 为什么直接给 exports 赋值会失效?

核心原因在于:exports 只是 module.exports 的一个引用副本。在 factory 内部重新为 exports 赋值时,仅仅改变了 exports 的指向,而 module.exports 依然指向原来的空对象。最终模块返回的是 module.exports 所引用的对象,你新赋值的对象被完全丢弃。

module.exports 对象详解

module.exports 才是当前模块真正的对外接口。传给 factory 构造方法的 exports 参数,实质上就是 module.exports 对象的一个引用。

只依赖 exports 参数来提供接口,在某些场景下会受限。例如,当模块需要返回一个类的实例时,必须借助 module.exports

define(function(require, exports, module) {
  // exports 是 module.exports 的一个引用
  console.log(module.exports === exports); // true
  // 重新给 module.exports 赋值
  module.exports = new SomeClass();
  // 此时 exports 不再等于 module.exports
  console.log(module.exports === exports); // false
});

⚠️ 重要提示:对 module.exports 的赋值必须同步执行,不能放在异步回调中。 下面这种写法是典型的陷阱:

// x.js
define(function(require, exports, module) {
  // 错误用法:异步赋值无效
  setTimeout(function() {
    module.exports = { a: "hello" };
  }, 0);
});

在其他模块中引用 x.js 时,会立即执行 require('./x'),但此时 module.exports 的赋值还在定时器队列中排队,根本无法获取到最终结果:

// y.js
define(function(require, exports, module) {
  var x = require('./x');
  // 无法立刻获取模块 x 的属性 a
  console.log(x.a); // undefined
});

综上所述,exports 适用于简单场景下逐个添加属性;module.exports 则适合需要替换整个对象或异步构造模块的情况。只要牢记“引用”这一本质,大多数问题就能迎刃而解。

来源:https://www.jb51.net/article/125718.htm
上一篇SeaJS最常用的7个功能详解及配置示例完整版 下一篇Seajs强制刷新本地缓存的实用方法详解
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
HTML文档版权声明结构与基础脚手架代码质量解析
前端开发 · 2026-07-07

HTML文档版权声明结构与基础脚手架代码质量解析

版权声明需用语义化``标签,©符号使用`©`实体;年份通过服务端、构建或JS分层兜底;`rel= "license "`仅指向真实许可证文件才有效。

基于HTML模板的组件化全栈交互方案
前端开发 · 2026-07-07

基于HTML模板的组件化全栈交互方案

纯HTML模板仅作静态结构,全栈交互需后端注入数据、前端JS激活模板及用户事件触发双向链路。``标签惰性,不执行脚本或加载资源,需通过克隆填充数据并手动绑定事件实现交互,父子传值依赖JS对象与自定义事件。

Bootstrap修改Badge徽章边框为圆点样式的方法
前端开发 · 2026-07-07

Bootstrap修改Badge徽章边框为圆点样式的方法

将BootstrapBadge改为圆点:自定义类设置等宽高、border-radius:50%、padding:0、font-size:0;Bootstrap5 2+需加display:inline-block;注意垂直对齐,避免min-width干扰,背景色用background-color更可控。

Bootstrap响应式多栏Footer社交图标排版实现
前端开发 · 2026-07-07

Bootstrap响应式多栏Footer社交图标排版实现

使用Bootstrap5的grid系统实现响应式多栏Footer,按断点设置列宽;以FontAwesome处理社交图标,避免使用img;利用list-unstyled组织链接列表;借助flex-column容器配合mt-auto使版权行自动贴底,避免fixed-bottom固定定位的弊端。

如何用Shadow DOM隔离组件内外事件分发
前端开发 · 2026-07-07

如何用Shadow DOM隔离组件内外事件分发

ShadowDOM内部事件默认不穿透影子边界,需显式设置composed:true才能被外部监听。此时event target指向宿主元素,真实触发源需通过event composedPath()[0]获取。原生事件手动派发时也必须声明composed:true。应避免在宿主上依赖event target做逻辑分支,建议在shadowroot内绑定事件或使用