common.js
CommonJS 是一种模块系统,主要用于 Node.js 环境。它使用 require 函数来引入模块,并使用 module.exports 来导出模块。
语法:
- 导出模块:
javascript
// moduleA.js
const name = 'Jo';
module.exports = name;
// 或者导出一个对象
const person = { name: 'Jo', age: 18 };
module.exports = person;
- 引入模块:
javascript
// main.js
const name = require('./moduleA');
console.log(name); // 'John'
// 引入对象
const person = require('./moduleA');
console.log(person.name); // 'Jo'
console.log(person.age); // 18
CommonJS的特点
- 同步加载模块:CommonJS 使用同步的方式加载模块,这意味着当一个模块被加载时,它会阻塞后续代码的执行,直到该模块完全加载并执行完毕。
javascript
// 模块A
console.log("Module A is being executed.");
module.exports = "This is module A.";
// 入口文件
console.log("Before requiring module A.");
const moduleA = require('./moduleA');
console.log("After requiring module A.")
- 模块导出:在 CommonJS 中,使用 module.exports 来导出模块的内容。这可以是任何类型的值,包括对象、函数、类等。
javascript
// 模块B
const sum = (a, b) => a + b;
module.exports = sum;
// 入口文件
const sumFunction = require('./moduleB');
console.log(sumFunction(2, 3)); // 输出 5
-
模块导入:使用 require() 函数来导入其他模块的内容。例如,const moduleA = require('./moduleA') 将会加载 moduleA.js 并将其导出的内容赋值给 moduleA。
-
单例模块:在 CommonJS 中,每个模块只会被加载一次,并且在内存中缓存,之后再次导入该模块时,都会返回相同的实例。这样可以减少资源消耗并提高性能。
javascript
// 模块C
class MyClass {
constructor() {
this.counter = 0;
}
incrementCounter() {
this.counter++;
}
}
module.exports = new MyClass();
// 入口文件
const singletonInstance1 = require('./moduleC');
const singletonInstance2 = require('./moduleC');
singletonInstance1.incrementCounter();
console.log(singletonInstance2.counter); // 输出 1
-
服务器端使用广泛:由于 CommonJS 最初是为服务器端 JavaScript(如 Node.js)设计的,因此在服务器端 JavaScript 开发中得到了广泛应用。
-
适用于大型应用:CommonJS 适用于构建大型应用程序,因为它可以帮助将代码组织成模块,并且提供了清晰的模块导入和导出机制,使得代码更易于维护和管理。
总的来说,CommonJS 提供了一种简单而强大的模块化方案,尤其适用于服务器端 JavaScript 开发以及构建大型应用程序。
ES6 模块
ES6 模块系统是 ECMAScript 标准的一部分,使用 import 和 export 语法来定义模块,广泛用于现代前端开发以及一些支持 ES6 的服务器环境。
语法
- 导出模块:
javascript
// moduleA.js
export const name = 'Jo';
// 导出默认值
const person = { name: 'Jo', age: 18 };
export default person;
- 引入模块:
javascript
// main.js
import { name } from './moduleA';
console.log(name); // 'Jo'
// 引入默认导出
import person from './moduleA';
console.log(person.name); // 'Jo'
console.log(person.age); // 18
ES6 模块的特点
-
静态导入和导出:ES6 模块的导入和导出是静态的,意味着模块的导入和导出关系在代码解析阶段就能确定,而不是在运行时。这使得工具可以更容易地分析和优化模块之间的依赖关系。
-
单例导入:与 CommonJS 不同,ES6 模块导入的是模块的绑定值的引用,而不是导出对象本身的副本。这意味着在不同模块中引用相同导出的变量,实际上引用的是同一个内存地址,这种行为被称为单例导入。
-
导出方式:ES6 模块的导出方式更加灵活,可以一次导出多个变量或函数,并且支持默认导出和命名导出两种方式。
javascript
// moduleA.js
export const name = "John";
export const age = 30;
// moduleB.js
const greeting = "Hello";
function sayHello() {
console.log(`${greeting}, ${name}! You are ${age} years old.`);
}
export { greeting, sayHello };
- 导入方式:ES6 模块的导入语法使用了 import 关键字,并支持默认导入、命名导入和命名空间导入。
javascript
// main.js
import { name, age } from './moduleA';
import { greeting, sayHello } from './moduleB';
console.log(`${greeting}, ${name}! You are ${age} years old.`);
sayHello();
- 异步加载:ES6 模块支持动态导入,可以在运行时动态加载模块。这种异步加载的方式能够提高应用程序的性能和响应速度。
javascript
// main.js
document.getElementById('button').addEventListener('click', async () => {
const module = await import('./moduleA');
console.log(module.name); // 输出 "John"
});
-
编译时优化:由于 ES6 模块的导入和导出关系在代码解析阶段就能确定,因此工具可以进行更有效的编译时优化,例如无用代码删除(tree shaking)等。
-
浏览器支持:与 CommonJS 不同,ES6 模块是 ECMAScript 标准的一部分,因此得到了浏览器原生支持,无需使用工具转换成其他格式。
总的来说,ES6 模块具有静态导入和导出、单例导入、灵活的导出方式、异步加载等特点,适用于现代 JavaScript 应用程序的开发,并且在浏览器和 Node.js 等环境中都得到了广泛应用。
CommonJS和ES6的兼容性和转换
CommonJS 是 Node.js 等环境中使用的模块系统,而 ES6 模块是 ECMAScript 2015 引入的新的模块化系统。它们之间存在一些兼容性和转换的问题。
- 兼容性:
- 在 Node.js 环境中,通常原生支持 CommonJS 模块,但对于 ES6 模块需要使用 --experimental-modules 标志启用,并且语法上也有一些不同。
- 在浏览器环境中,原生支持 ES6 模块,但对于 CommonJS 模块,需要使用工具如 Browserify 或 Webpack 进行转换后才能在浏览器中运行。
- 转换:
- 使用 Babel 可以将 ES6 模块转换为 CommonJS 或 AMD 格式,以便在不支持 ES6 模块的环境中运行。
- 对于 Node.js 中的 CommonJS 模块,可以使用工具将其转换为 ES6 模块,以便在支持 ES6 模块的环境中使用。
javascript
// ES6 模块
// es6Module.js
export const foo = "Hello";
// 转换为 CommonJS 格式
// commonJSModule.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.foo = "Hello";
通过使用 Babel 进行转换,可以让不同模块系统之间的代码在不同环境中运行和使用。在实际开发中,通常会根据目标环境和需求选择合适的模块系统,并使用相应的工具进行转换和兼容性处理。
使用场景
CommonJS 的使用场景:
- 服务器端开发:Node.js 原生支持 CommonJS 模块,因此在服务器端开发中,特别是使用 Node.js 进行后端开发时,常常会选择使用 CommonJS 模块。
- 同步加载:CommonJS 模块是同步加载的,适合于服务器端的同步加载模块的环境。
- 动态加载:CommonJS 允许在运行时动态加载模块,这使得它在某些需要动态加载的情况下更为适用。
- 模块化封装:CommonJS 模块更适合于封装和组织代码,尤其是对于那些需要将功能打包为模块并在不同项目中重复使用的情况。
ES6 模块的使用场景:
- 浏览器端开发:现代浏览器原生支持 ES6 模块,因此在前端开发中,特别是使用现代浏览器的前端开发时,常常会选择使用 ES6 模块。
- 静态加载:ES6 模块是静态加载的,这意味着在解析阶段就已经确定模块的依赖关系,适合于前端项目中对模块依赖有明确要求的情况。
- 异步加载:ES6 模块支持异步加载,可以通过 import() 函数实现按需加载,这使得它在前端项目中更适用于动态加载和按需加载的场景。
- 模块化打包:使用工具如 Webpack、Rollup 等可以将 ES6 模块打包成浏览器可识别的代码,这样可以将多个模块打包成一个或多个文件,减少网络请求,提高加载效率。
综上所述,CommonJS 更适用于服务器端开发和同步加载的场景,而 ES6 模块更适用于浏览器端开发和静态加载的场景。在选择使用模块系统时,应根据具体的项目需求和目标环境做出合适的选择。