JS模块介绍

来源于 ES6模块和CommonJS模块有哪些差异 的提问。

文章目录

  • 什么是JS模块化
  • 为什么要JS模块化
  • 如何实现JS模块化
  • 现有的JS模块化方案有哪些
    • CommonJS
        • 模块循环依赖
    • AMD规范
    • CMD规范
    • ES6规范

  • 什么是JS模块化?
  • 为什么要JS模块化?
  • 如何实现JS模块化?
  • 现有的JS模块化方案有哪些?

什么是JS模块化

JS模块化,就是将js中的逻辑进行拆分,分别在每一个局部作用域中去做,明确好上下游的依赖关系。
举个例子,我点击一个按钮,发起一个请求,请求过来一堆数据,此时需要发送日志,这个数组需要经过一定的格式化过程,将数据应用到对应的模板上,在页面渲染出来。

Button.js  // 按钮模块,里面绑定了点击事件,并向外暴露出一个函数做后续处理
Http.js    // 请求模块,所有的请求通过这个模块暴露出的方法使用
Log.js     // 日志模块,可以放到Http模块里,监控http发送的状态和内容
Format.js  // 格式化模块,这块和业务相关,可以做成纯函数,格式化出自己想要的数据结构
Template.js // 模板模块,传入模板和数据,返回需要渲染的HTML 
点击发起请求
日志监控
和Format生成模板
和Http生成模板
Button
Http
Log
Format
Template

为什么要JS模块化

模块的优点

  • 可维护性。 因为模块是独立的,一个设计良好的模块会让外面的代码对自己的依赖越少越好,这样自己就可以独立去更新和改进。
  • 命名空间。 在 JavaScript 里面,如果一个变量在最顶级的函数之外声明,它就直接变成全局可用。因此,常常不小心出现命名冲突的情况。使用模块化开发来封装变量,可以避免污染全局环境。
  • 重用代码。 我们有时候会喜欢从之前写过的项目中拷贝代码到新的项目,这没有问题,但是更好的方法是,通过模块引用的方式,来避免重复的代码库

如何实现JS模块化

// 将各个功能方法封装在一个单独的对象中

var Http = function(){
	var func1 = () => {};
	var func2 = () => {};
	
	return {
		func1,
		func2
	} 
}

var Log = function(){
	var func1 = () => {};
	var func2 = () => {};
	
	return {
		func1,
		func2
	} 
}

// 使用方法,虽然func1都是同名,但是封装在不同的对象里,不会污染全局
Http.func1();
Log.func1();

现有的JS模块化方案有哪些

以下是现有的一些关于JS模块的解决方案

  • CommonJS规范,使用框架node
  • AMD规范,使用框架 requireJs
  • CMD规范,使用框架 seaJs
  • ES6规范

CommonJS

CommonJS是一个项目,其目标是为JavaScript在网页浏览器之外创建模块约定。创建这个项目的主要原因是当时缺乏普遍可接受形式的JavaScript脚本模块单元,模块在与运行JavaScript脚本的常规网页浏览器所提供的不同的环境下可以重复使用。 — wiki百科

Node 应用由模块组成,采用 CommonJS 模块规范。

使用方法:

// module1.js
var module1 = function(param){
	console.log('module1', param)
};
var MODULE_VAR = 'module1';

module.exports = {
	module1,
	MODULE_VAR
}
// module2.js
var { module1, MODULE_VAR  } = require('./module1.js');
module1('module2'); // 输出 'module1, module2'

CommonJS规范,通过require导入,module.exports导出,导出的内容本身是一个对象。

module 本身是node提供的一个api,其中包含以下属性

|
| - children   当前模块被用于的模块
| - exports    当前模块导出的接口,本身是个对象
| - filename   带有绝对路径的文件名
| - id         当前模块id
| - loaded     当前模块是否已经被加载
| - parent     当前模块引入的模块
| - paths      多种类型的文件路径

JS模块介绍_第1张图片

模块循环依赖

// a.js
exports.x = 'a1';
console.log('a.js ', require('./b.js').x);
exports.x = 'a2';

// b.js

exports.x = 'b1';
console.log('b.js ', require('./a.js').x);
exports.x = 'b2';

// 执行node b
输出
a.js  b1
b.js  a2

模块只加载一部分

CommonJS模块的特点如下:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

具体内容可以查看 阮一峰的博客

AMD规范

CMD规范

ES6规范

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

使用方法:

// module1.js
var moduleName = '鬼谷中妖';
var module1 = function(){
	console.log('words', words);
};

export { 
	moduleName as nn, 
	module1 as n1
};
// module2.js
import { nn, n1 } = from './module1.js';
n1(nn); // words,'鬼谷中妖'

具体内容可以查看 阮一峰的博客模块


回到提问:

  1. 使用语法不同
  2. CommonJS,导入导出的是对象,是动态引用。ES6,导出的是当前使用其他模块方法的代码,属于静态编译,类似C#应用,在编译时就会提示语法错误。

https://github.com/YvetteLau/Step-By-Step/issues/43

参考:

  • 阮一峰 ES6 Module 的语法
  • CommonJS模块介绍

你可能感兴趣的:(前端)