前端模块化

问题的出现

随着 web 技术的发展,前端的项目会越来越大,所以现在项目都是使用组件化的模式进行前端开发,在这种情况下,传统开发会有许多问题,例如:

  • 命名冲突和污染
  • 代码冗余,无效请求多
  • 文件间的依赖关系复杂
    这些问题会让项目变得难以维护且不方便复用

而模块化可以解决这个问题,模块就是小而精且利于维护的代码片段,模块化是前端走向工程化中的重要一环,早期 JavaScript 语言层面没有模块化规范,更多的是程序员利用函数、对象、自执行函数实现分块,后来慢慢的由个人或社区产出了 Commonjs、AMD、CMD 这样的模块化规范,之后在 ES6 中,将 ES modules 纳入了标准规范,当下最常用的规范是 Commonjs 和 ESM,Commonjs 用于 node 平台下的开发,ESM 用于浏览器平台下的开发。

Commonjs

  • 在 commonjs 中每一个 js 文件都是一个单独的模块,我们可以称之为 module;
  • 该模块中,包含 CommonJS 规范的核心变量: exports、module.exports、require;
  • exports 和 module.exports 可以负责对模块中的内容进行导出;
  • require 函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容;

示例代码:
router.js 为要导出的模块,server.js 为要引用 router.js 的模块
router.js

// 可以直接给exports对象赋值导出
exports={
    forward: function(){...},
    back:  function(){...}
}
// 或者可以直接给exports添加属性
exports.forward=function(){...};
exports.back=function(){...};

server.js

// 使用require函数导入
const router = require("./router.js");
router.forward();
// 也可使用解构赋值,只导入这个模块的某一个方法来使用
const { forward } = require("./router.js");
forward();

ES modules

想要在浏览器端使用 ES module,在引入 js 文件时,需将 script 标签中的 type 设置为 module
index.html

<script src="main.js" type="module"></script>

定义之后就可以在对应的 js 文件中使用模块化的方式来编写文件,使用 export 导出模块,使用 import 导入模块

示例:

  1. 直接导出定义的变量
    a.js
export const name = "rido";
export const age = 18;

b.js

import { name, age } from "./a.js";
console.log(name, age);
  1. 使用 export 一起导出,导入时可以通过 * 来将所有的导出内容定义为一个对象,从对象中再去取值

a.js

const name = "rido";
const age = 18;
export { name, age };

b.js

import * as obj from "./a.js";
console.log(obj.name, obj.age);
  1. 给导入导出的变量取别名

a.js

const name = "rido";
const age = 18;

export { name as myName, age as myAge };

b.js

import { myName as ridoName, myAge } from "./a.js";

console.log(ridoName, myAge); // rido 18
  1. 默认导出,默认导出在一个 js 文件中只允许存在一个,默认导出可以不用定义变量名,在导入的时候可以随意起名,并且导入的时候不需要加 {}

a.js

export default function () {
  return "hello world";
}

b.js

import foo from "./a.js";

console.log(foo()); // hello world

Q.E.D.


永远自由,永远热爱