JavaScript模块化规范

.JavaScript模块化规范

1.模块化概述

1 什么事模块化?

模块化是指将一个复杂的程序按照一定的规范或设计思想,

拆分成若干个独立、可复用的模块,每个模块负责完成特定的功能,

并通过明确的接口与其他模块进行组合和交互。

2 为什么需要模块化?

在早期的前端开发中,代码往往写在一个全局作用域里,容易产生以下问题:

  • 命名冲突:多个变量、函数同名,相互覆盖。
  • 依赖混乱:文件之间的加载顺序必须手动保证,难以维护。
  • 代码复用困难:复制粘贴代码导致重复和冗余。
  • 难以测试:大段耦合代码难以单独测试。
    3.模块化解决了这些问题,带来:
  • 高内聚、低耦合:每个模块专注自己的职责。
  • 按需加载:只加载需要的模块,提升性能。
  • 依赖管理清晰:通过 import / require 明确声明依赖关系。
  • 易于维护和协作:多人可并行开发不同模块,代码结构清晰。

2.有哪些模块化规范?

1 commonJS -服务端应该广泛

2.AMD

3.CMD

4.ES 模块化浏览器应用广泛

3 commonJS 使用

3.1 初步体验

a.js

javascript 复制代码
const name='张三'
function fn(){
	return '你好'
}
exports.fn=fn; //导出
exports.name=name

b.js

javascript 复制代码
// 注意:路径需要正确,如果是同一目录,应为 './a.js'
const a = require('./a.js'); 
console.log(a.name);   // 输出:张三
console.log(a.fn());   // 输出:你好

require 的路径规则:

  • 核心模块(如 fs、path):直接写模块名 require('fs')
  • 自定义模块:使用相对路径 require('./a.js') 或 require('.../lib/a.js')
  • 文件夹模块:如果 require 一个目录,会查找该目录下的 index.js

3.2 导出数据

在coomonjs标准中,导出数据有两种格式

第一种:module.exports = value

  • value 可以是任意类型:对象、函数、字符串、类等。
  • 会完全覆盖默认的导出对象,最终导出就是这个 value。
javascript 复制代码
// person.js
module.exports = { name: '李四', age: 20 };
// 或者
module.exports = function() { console.log('hello'); };

第二种格式exports.name = value

  • exports 是 module.exports 的一个引用。
  • 通过给 exports 添加属性,本质上是给 module.exports 添加属性。
  • 不能直接给 exports 赋值(如 exports = { a: 1 }),因为那会切断引用。
javascript 复制代码
// utils.js
exports.add = (x, y) => x + y;
exports.sub = (x, y) => x - y;
// 等价于:
// module.exports.add = (x, y) => x + y;
// module.exports.sub = (x, y) => x - y;

3.3面试题

javascript 复制代码
exports ={1:1}
exports.b=2
module.exports.c=3
module.exports ={d:4}

//合并之后是{d:4}

*无论如何修改对象,最后导出的格式都是module.exports

导出之后 也可以进行解析引入

3.4 导入(require)的细节

javascript 复制代码
const someModule = require('./module.js');

require 的特性

  • 同步加载:模块代码会按顺序执行,加载完成才继续。
  • 缓存机制 :同一个模块多次 require,只会执行一次,后续返回缓存中的导出对象。
    -加载非 JS 文件:可以通过自定义扩展名加载 JSON、Node 插件等。例如 require('./data.json') 会自动解析为对象

解构导入

javascript 复制代码
const { fn, name } = require('./a.js');
console.log(fn(), name);

3.5 注意事项

不要混用两种导出方式时产生覆盖

javascript 复制代码
exports.a = 1;
module.exports = { b: 2 };  // 前面的 exports.a 会被覆盖,最终只导出 { b: 2 }

循环依赖:CommonJS 遇到循环依赖时,会输出当前已执行部分的内容(可能不完整),需谨慎设计。

文件扩展名可省略:require('./a') 会依次尝试 .js、.json、.node。

在 ES Module 中使用 CommonJS:可通过 import 或 createRequire 实现,但不推荐混合。

3.6 小结

导出方式 语法 最终导出内容

默认导出对象 module.exports = obj obj

添加属性 exports.prop = value module.exports 对象上增加属性

直接给 exports 赋值 exports = something ❌ 无效,导出的仍是原 module.exports
记忆口诀:

导出看 module.exports,

exports 只是小别名。

若要覆盖直接赋,

添加属性用点行。

4.ES6规范

ES6 模块化规范是官方标准,语言层面支持,浏览器和 Node.js 均可原生使用。它采用 import/export 语法,支持静态分析、树摇(tree shaking)、循环依赖处理优于 CommonJS。Node 环境中启用方式:使用 .mjs 后缀,或在 package.json 中设置 "type": "module"。

4.1 初步体验

a.js(导出模块)

javascript 复制代码
// 命名导出
export const name = '张三';
export function fn() {
    return '你好';
}

b.js(导入模块)

javascript 复制代码
// 命名导入
import { name, fn } from './a.js';
console.log(name);   // 张三
console.log(fn());   // 你好

注意:ES6 Module 默认使用严格模式,且必须在支持 ES Module 的环境中运行(浏览器

4.2 导出数据(export)

ES6 Module 提供了多种导出方式:

4.2.1 命名导出(Named Export)

可以导出多个变量、函数、类。

导出后必须通过相同的名称导入(可用 as 重命名)。

javascript 复制代码
// 方式1:声明时直接导出
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export class Calculator { ... }

// 方式2:先声明,后统一导出
const a = 1;
const b = 2;
export { a, b };

// 方式3:重命名导出
const c = 3;
export { c as myC };

4.2.2 默认导出(Default Export)

  • 每个模块只能有一个默认导出。
  • 导入时可以使用任意名称。
javascript 复制代码
// 方式1:直接导出匿名值
export default function() {
    console.log('default function');
}

// 方式2:导出已命名的变量/函数/类
const myObj = { x: 10 };
export default myObj;

// 方式3:混合导出(命名 + 默认)
export const version = '1.0';
export default class Main { ... }

4.3 导入数据(import)

4.3.1 命名导入

javascript 复制代码
import { name, age } from './person.js';
import { name as userName } from './person.js';   // 重命名

4.3.2 默认导入

javascript 复制代码
import anyName from './module.js';  // 任意名称,对应 default 导出

4.3.3 混合导入

javascript 复制代码
import defaultExport, { named1, named2 } from './module.js';

4.3.4 整体导入(命名空间导入)

javascript 复制代码
import * as myModule from './module.js';
console.log(myModule.named1);
console.log(myModule.default);  // 注意:default 需要 .default 访问

4.3.5 动态导入(运行时)

javascript 复制代码
const module = await import('./some.js');
module.someMethod();

4.4 ES6 Module 的重要特性

1.静态结构:import/export 必须在模块顶层,不能写在条件语句或函数中。这支持了 Tree Shaking(打包时删除未使用的导出)。

2.实时绑定(Live Binding):导入的是导出值的引用,模块内部值变化会反映到导入方。

3.异步加载:适用于浏览器,支持

4.5问:CommonJS 和 ES Module 的本质区别是什么?

答:CommonJS 是运行时加载,模块是对象,输出的是值的拷贝。

ES Module 是编译时加载,模块是静态结构,输出的是值的只读引用,支持 Tree Shaking。

ES Module 的 import 会被提升到模块顶部,且不能在块级作用域中使用;CommonJS 的 require 可以在任何地方动态调用。

相关推荐
三万棵雪松2 小时前
【Linux 物联网网关主控系统-Web部分(四)】
linux·前端·物联网·嵌入式linux
Dream of maid2 小时前
Python基础4(函数)
开发语言·python
摸鱼的春哥2 小时前
Agent教程22:AI大模型兼容,踩坑到崩溃
前端·javascript·后端
lingggggaaaa2 小时前
PHP模型开发篇&MVC层&RCE执行&文件对比法&1day分析&0day验证
开发语言·学习·安全·web安全·php·mvc
regret~2 小时前
【记录】前端创建
前端
独特的螺狮粉2 小时前
开源鸿蒙跨平台Flutter开发:跨越 OOM 内存崩溃陷阱:基于 async* Generator 与流式 I/O 的生命科学数据底座构筑
开发语言·flutter·开源·harmonyos
jwn9992 小时前
Laravel2.x:探索PHP框架的起源
开发语言·php
深念Y2 小时前
前端实时通信技术:HTTP轮询、SSE、WebSocket、WebRTC
前端·websocket·网络协议·http·实时互动·轮询·实时通信
希望永不加班2 小时前
SpringBoot 多模块项目搭建:service/dao/web分层设计
java·前端·spring boot·后端·spring