JavaScript 模块化规范详解 CommonJS,ES6模块化

JavaScript 模块化规范详解

1. 模块化概述

1.1. 什么是模块化?

将程序文件依据一定规则拆分成多个文件,这种编码方式就是模块化的编码方式。拆分出来的每个文件就是一个模块,模块中的数据都是私有的,模块之间互相隔离。同时也能通过一些手段,可以把模块内的指定数据"交出去",供其他模块使用。

1.2. 为什么需要模块化?

随着应用的复杂度越来越高,其代码量和文件数量都会急剧增加,会逐渐引发以下问题:

  1. 全局污染问题
  2. 依赖混乱问题
  3. 数据安全问题

2. 有哪些模块化规范?

按时间排序,分别为:

  1. CommonJS ------ 服务端应用广泛
  2. AMD
  3. CMD
  4. ES6 模块化 ------ 浏览器端应用广泛

3. 导入与导出的概念

模块化的核心理想就是:模块之间是隔离的,通过导入和导出进行数据和功能的共享。

  • 导出(暴露) :模块公开其内部的一部分(如变量、函数等),使这些内容可以被其他模块使用。
  • 导入(引入) :模块引入和使用其他模块导出的内容,以重用代码和功能。

4. CommonJS 规范

4.1. 初步体验

创建 school.js

JavaScriptCopy

javascript 复制代码
const name = 'hellowword';
const slogan = '青花瓷!';
function getTel() {
  return '010-56253825';
}
function getCities() {
  return ['北京', '上海', '深圳', '成都', '武汉', '西安'];
}
// 通过给 exports 对象添加属性的方式,来导出数据(注意:此处没有导出 getCities)
exports.name = name;
exports.slogan = slogan;
exports.getTel = getTel;
创建 student.js

JavaScriptCopy

javascript 复制代码
const name = 'berlvy';
const motto = 'sumu!';
function getTel() {
  return '1234';
}
function getHobby() {
  return ['北京', '上海', '深圳', '成都', '武汉', '西安'];
}
// 通过给 exports 对象添加属性的方式,来导出数据(注意:此处没有导出 getHobby)
exports.name = name;
exports.slogan = slogan;
exports.getTel = getTel;
创建 index.js

JavaScriptCopy

ini 复制代码
// 引入 school 模块暴露的所有内容
const school = require('./school');
// 引入 student 模块暴露的所有内容
const student = require('./student');

4.2. 导出数据

在 CommonJS 标准中,导出数据有两种方式:

  1. 第一种方式:module.exports = value
  2. 第二种方式:exports.name = value

注意点如下:

  1. 每个模块内部的 thisexportsmodule.exports 在初始时,都指向同一个空对象,该空对象就是当前模块导出的数据。
  2. 无论如何修改导出对象,最终导出的都是 module.exports 的值。
  3. exports 是对 module.exports 的初始引用,仅为了方便给导出对象添加属性,所以不能使用 exports = value 的形式导出数据,但是可以使用 module.exports = xxxx 导出数据。

4.3. 导入数据

在 CJS 模块化标准中,使用内置的 require 函数进行导入数据

JavaScriptCopy

javascript 复制代码
// 直接引入模块
const school = require('./school');
// 引入同时解构出要用的数据
const { name, slogan, getTel } = require('./school');
// 引入同时解构+重命名
const { name: stuName, motto, getTel: stuTel } = require('./student');

4.4. 扩展理解

一个 JS 模块在执行时,是被包裹在一个内置函数中执行的,所以每个模块都有自己的作用域,我们可以通过如下方式验证这一说法:

JavaScriptCopy

javascript 复制代码
console.log(arguments);
console.log(arguments.callee.toString());

内置函数的大致形式如下:

JavaScriptCopy

markdown 复制代码
function (exports, require, module, __filename, __dirname) {
  /*********************/
}

4.5. 浏览器端运行

Node.js 默认是支持 CommonJS 规范的,但浏览器端不支持,所以需要经过编译,步骤如下:

  • 第一步:全局安装 browserify :npm i browserify -g
  • 第二步:编译:browserify index.js -o build.js
  • 第三步:页面中引入使用:<script type="text/javascript" src="./build.js"></script>

5. ES6 模块化规范

ES6 模块化规范是一个官方标准的规范,它是在语言标准的层面上实现了模块化功能,是目前最流行的模块化规范,且浏览器与服务端均支持该规范。

5.1. 初步体验

创建 school.js

JavaScriptCopy

javascript 复制代码
// 导出 name
export let name = { str: '苏木' };
// 导出 slogan
export const slogan = '苏木Berlvy!';
// 导出 name
export function getTel() {
   return '1234';
}
function getCities() {
  return ['1', '2', '3', '4', '5', '6'];
}
创建 student.js

JavaScriptCopy

javascript 复制代码
// 导出 name
export const name = 'sumu11';
// 导出 motto
export const motto = '相信明天会更好!';
// 导出 getTel
export function getTel() {
  return '13877889900';
}
function getHobby() {
  return ['1', '2', '3'];
}
创建 index.js

JavaScriptCopy

javascript 复制代码
// 引入 school 模块暴露的所有内容
import * as school from './school.js';
// 引入 student 模块暴露的所有内容
import * as student from './student.js';
页面中引入 index.js

HTMLCopy

xml 复制代码
<script type="module" src="./index.js"></script>

Preview

5.2. Node 中运行 ES6 模块

Node.js 中运行 ES6 模块代码有两种方式:

  • 方式一:将 JavaScript 文件后缀从 .js 改为 .mjs,Node 则会自动识别 ES6 模块。
  • 方式二:在 package.json 中设置 type 属性值为 module。

5.3. 导出数据

ES6 模块化提供 3 种导出方式:①分别导出、②统一导出、③默认导出

分别导出

JavaScriptCopy

javascript 复制代码
// 导出 name
export let name = { str: '苏木1' };
// 导出 slogan
export const slogan = 'berlvy!';
// 导出 getTel
export function getTel() {
  return '010-56253825';
}
统一导出

JavaScriptCopy

javascript 复制代码
const name = { str: '苏木1' };
const slogan = 'berlvy!';
function getTel() {
  return '010-56253825';
}
function getCities() {
  return ['1', '2', '3', '4', '5', '6'];
}
// 统一导出:name, slogan, getTel
export { name, slogan, getTel };
默认导出

JavaScriptCopy

javascript 复制代码
const name = '苏木';
const motto = 'berlvy!';
function getTel() {
  return '13877889900';
}
function getHobby() {
  return ['1', '2', '3'];
}
// 默认导出:name, motto, getTel
export default { name, motto, getTel };

5.4. 导入数据

对于 ES6 模块化来说,使用何种导入方式,要根据导出方式决定。

导入全部

JavaScriptCopy

javascript 复制代码
import * as school from './school.js';
命名导入

JavaScriptCopy

javascript 复制代码
import { name, slogan, getTel } from './school.js';
import { name as myName, slogan, getTel } from './school.js';
默认导入

JavaScriptCopy

javascript 复制代码
import student from './student.js'; // 默认导出的名字可以修改,不是必须为 student
命名导入与默认导入混合使用

JavaScriptCopy

javascript 复制代码
import getTel, { name, slogan } from './school.js';

5.5. 数据引用问题

思考1:如下代码的输出结果是什么?(不要想太多,不涉及模块化相关知识)

JavaScriptCopy

scss 复制代码
function count() {
  let sum = 1;
  function increment() {
    sum += 1;
  }
  return { sum, increment };
}
const { sum, increment } = count();
console.log(sum);
increment();
increment();
console.log(sum);

6. AMD 模块化规范(了解)

6.1. 环境准备

文件说明:

  1. js 文件夹中存放业务逻辑代码,main.js 用于汇总各模块。
  2. libs 中存放的是第三方库,例如必须要用的 require.js。

在 index.html 中配置 main.js 与 require.js:

HTMLCopy

xml 复制代码
<script data-main="./js/main.js" src="./libs/require.js"></script>

Preview

6.2. 导出数据

AMD 规范使用 define 函数来定义模块和导出数据。如需导入数据,则需要 define 传入两个参数,分别为:依赖项数组、回调函数。

JavaScriptCopy

javascript 复制代码
define(function () {
const name = '苏木';
const motto = 'berlvy!';
function getTel() {
  return '13877889900';
}
function getHobby() {
  return ['1', '2', '3'];
}
  // 导出数据
  return { name, motto, getTel };
});

6.3. 导入数据

JavaScriptCopy

php 复制代码
/* AMD_require.js 模块化的入口文件,要编写配置对象,并且有固定的写法 */
requirejs.config({
  // 基本路径
  baseUrl: './js',
  // 模块标识名与模块路径映射
  paths: {
    school: 'school',
    student: 'student',
    welcome: 'welcome',
  },
});

6.4. 使用模块

JavaScriptCopy

javascript 复制代码
requirejs(['school', 'student'], function (school, student) {
  console.log('main', school);
  console.log('main', student);
});

7. CMD 模块化规范(了解)

7.1. 环境准备

文件说明:

  1. js 文件夹中存放业务逻辑代码,main.js 用于汇总各模块。
  2. libs 中存放的是第三方库,例如必须要用的 sea.js。

在 index.html 中配置 main.js 与 sea.js:

HTMLCopy

xml 复制代码
<script type="text/javascript" src="./libs/sea.js"></script>
<script type="text/javascript">
  seajs.use('./modules/main.js');
</script>

Preview

7.2. 导出数据

CMD 规范中同样使用 define 函数定义模块并导出数据。

JavaScriptCopy

javascript 复制代码
define(function (require, exports, module) {
  const name = '苏木';
  const slogan = 'berlvy!';
  function getTel() {
    return '010';
  }
  function getCities() {
    return ['1', '2', '3', '4', '5', '6'];
  }
  // 导出数据
  module.exports = { name, slogan, getTel };
});

7.3. 导入数据

JavaScriptCopy

javascript 复制代码
define(function (require, exports, module) {
  const name = '苏木';
  const motto = '你好呀!';
  // 引入 welcome 模块
  const welcome = require('./welcome');
  console.log(welcome);
  function getTel() {
    return '13877889900';
  }
  function getHobby() {
    return ['1', '2', '3'];
  }
  exports.name = name;
  exports.motto = motto;
  exports.getTel = getTel;
});

7.4. 使用模块

JavaScriptCopy

javascript 复制代码
define(function (require) {
  const school = require('./school');
  const student = require('./student');
  // 使用模块
  console.log(school);
  console.log(student);
});
相关推荐
冴羽3 分钟前
SvelteKit 最新中文文档教程(3)—— 数据加载
前端·javascript·svelte
云隙阳光i33 分钟前
实现手机手势签字功能
前端·javascript·vue.js
柠檬树^-^2 小时前
app.config.globalProperties
前端·javascript·vue.js
起来改bug2 小时前
【pptx-preview】react+pptx预览
javascript·react.js·pptx
马可奥勒留3 小时前
声明
javascript
团酱4 小时前
控制台报错:The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.
开发语言·javascript·sass
清羽_ls4 小时前
react useEffect函数清除副作用函数执行时机
前端·javascript·react.js
難釋懷5 小时前
JavaScript数据类型简介
前端·javascript
Riesenzahn5 小时前
TypeScript中支持的访问修饰符有哪些?
前端·javascript
打野赵怀真5 小时前
如何使用html5进行图片压缩上传?
前端·javascript