跳转到主要内容

主页内容

JavaScript模块化详解(一) CommonJS规范

由 webadmin 发布于 阅读 96 次

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.jsstudent.js,然后右击,选择【run code】。(如果没有这个选项需要先安装“Code Runner”插件。)

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

school.jsstudent.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、每个模块内部的:thisexportsmodules.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>