1、模块化概述
1.1、什么是模块化
- 将程序文件依据一定规则拆分成多个文件,这种编码方式就是模块化的编码方式。
- 拆分出来每个文件就是一个模块,模块中的数据都是私有的,模块之间互相隔离。
- 同时也能通过一些手段,可以把模块内的指定数据“交出去”,供其他模块使用。
1.2、为什么需要模块化?
随着应用的复杂度越来越高,其代码量和文件数量都会急剧增加,会逐渐引发以下问题:
- 全局污染问题
- 依赖混乱问题
- 数据安全问题
2、模块化规范
- CommonJS——服务端应用广泛
- AMD
- CMD
- ES6 模块化——浏览器端应用广泛
3、导入和导出的概念
模块化的核心思想就是:模块之间是隔离的,通过导入和导出进行数据和功能的共享。
- 导出(暴露):模块公开其内部的一部分(如变量、函数等),使这些内容可以被其他模块使用。
- 导入(引入):模块引入和使用其他模块导出的内容,以重用代码和功能。

4、CommonJS规范
4.1、初步体验
创建school.js:
const name = "清华大学";
const slogan = "是中国最难考的大学吗?";
function getTel(){
return "010-89898989";
}
function getCities(){
return ["北京","上海","天津"];
}
创建student.js
const name = "张三";
const motto = "明天会更好";
function getTel(){
return "13201567876";
}
function getHobby(){
return ["打篮球","踢足球","上网"];
}
创建main.js:
const school = require("./school.js");
const student = require("./student.js");
console.log(school);
console.log(student);
在main.js
文件中引入school.js
和student.js
,然后右击,选择【run code】。(如果没有这个选项需要先安装“Code Runner”插件。)

如下图所示,运行结果是两个空对象。无法接收到引入文件中的任何信息。原因是被引入的文件中没有任何内容被暴露(导出)。

在school.js
和student.js
文件中加入暴露(导出)的语法:
school.js:
const name = "清华大学";
const slogan = "是中国最难考的大学吗?";
function getTel(){
return "010-89898989";
}
function getCities(){
return ["北京","上海","天津"];
}
//以下是school导出的变量和方法。
exports.name = name;
exports.slogan = slogan;
exports.getCities = getCities;
student.js:
const name = "张三";
const motto = "明天会更好";
function getTel(){
return "13201567876";
}
function getHobby(){
return ["打篮球","踢足球","上网"];
}
//以下是student导出的变量和方法。
exports.name = name;
exports.motto = motto;
exports.getHobby = getHobby;
在main.js
再次点击【run code】,运行结果如下。
通过运行结果可以看出,两个文件中暴露出来的都可以被接收到,而没有暴露出来的则无法被接收。
4.2、导出(暴露)数据
在CommonJS
规范中,导出数据有2
种方式:
- 第1种方式:
module.exports = value;
- 第2种方式:
exports.name = value;
4.2.1、module.exports = value
方式的应用
const name = "清华大学";
const slogan = "是中国最难考的大学吗?";
function getTel(){
return "010-89898989";
}
function getCities(){
return ["北京","上海","天津"];
}
//原来的写法
// exports.name = name;
// exports.slogan = slogan;
// exports.getCities = getCities;
//用第一种方式的写法:
module.exports = { name, slogan, getCities };
需要注意的点:
1、每个模块内部的:
this
、exports
、modules.exports
在初始时,都指向同一个空对象,该空对象就是当前模块导出的数据,如下图:2、无论如何修改导出对象,最终导出的都是
module.exports
的值。如下这段代码体现了这一点。this.c = 789 exports = {a:1} exports.b = 2 module.exports.c = 3 module.exports = {d:4} //这段代码最终暴露出的数据是{d:4}。
3、
exports
是对module.exports
的初始引用,仅为了方便给导出象添加属性,所以不能使用exports = value
的形式导出数据,但是可以使用module.exports = xxxx
导出数据。
4.3、导入数据
在CommonJS 模块化标准中,使用内置的require
函数进行导入数据。
1、直接引入模块:
const school = require("./school.js");
2、引用的时候,直接解构出要用的数据。
const {name, slogan, getCities, getTel} = require("./school.js");
3、引入的同时,解构+重命名(存在同名的情况下需要重命名,否则名称会有冲突)
const {name:stuName, motto, getTel:stuGetTel} = require("./student.js");
4.4、扩展理解
一个JS 模块在执行时,是被包裹在一个内置函数中执行的,所以每个模块都有自己的作用域,我们可以通过如下方式验证这一说法:
const name = "张三";
const motto = "明天会更好";
function getTel(){
return "13201567876";
}
function getHobby(){
return ["打篮球","踢足球","上网"];
}
// module.exports = {name,motto, getTel};
console.log(arguments.callee.toString());//验证模块是否被包裹在函数中。

这个函数的代码如下:
function (exports, require, module, __filename, __dirname) {
const name = "张三";
const motto = "明天会更好";
function getTel(){
return "13201567876";
}
function getHobby(){
return ["打篮球","踢足球","上网"];
}
// module.exports = {name,motto, getTel};
console.log(arguments.callee.toString());
}
4.5、浏览器端运行
Node.js 默认是支持CommonJS 规范的,但浏览器端不支持,

所以需要经过编译,步骤如下:
1、全局安装browserify,官网地址:https://browserify.org/,命令:
npm i browserify -g
2、编译:
browserify main.js -o build.js
,其中main.js
是源文件,build.js
是输出的目标文件。(命令中-o
的意思是output
的意思)3、在页面中引入使用:
<script type="text/javascript" src="build.js"></script>
