编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。
把代码进行模块化拆分的好处:
- 事实上模块化开发最终的目的是将程序划分成一个个小的结构;
- 这个结构中编写属于自己的逻辑代码,有自己的作用域,不会影响到其他的结构;
- 这个结构可以将自己希望暴露的变量、函数、对象等导出给其结构使用
- 也可以通过某种方式,导入另外结构中的变量、函数、对象等
上面说提到的结构,就是模块;按照这种结构划分开发程序的过程,就是模块化开发的过程。
模块化常见的两种:
CommonJS
每个文件都可以当作一个模块
在服务端:模块的加载时运行时同步加载的
在浏览器端:模块需要提前编译打包处理
在浏览器端编译打包需要用到 browserify。打包命令 browserify app.js -o build.js
ES6
依赖模块需要编译打包处理
一、CommonJS
语法:
导入模块:require
导出模块:export
导出:
//在bar.js文件
// Node中每一个Js文件就是一个模块
const name = 'PengSir'
const age = 18
let message = 'My name is peng'
function sayHello(name) {
console.log('hello' + name);
}
// exports 默认是空对象
// console.log(exports); // {}
// 1.导出
exports.name = name
exports.age = age
exports.sayHello = sayHello
exports.message = message
导入:
//在main.js文件
// 导入:require 是一个函数
// const bar = require('./bar')
const {name,age,sayHello,message} = require('./bar')
console.log(name);// PengSir
在每个Node应用中都有一个 exports 对象,在其他文件导入某个文件时,其实就是拿到该对象的内存地址。bar对象是 exports 对象的浅拷贝(引用赋值)
require的细节:
require的加载过程是同步的,意味着必须等到引入的文件(模块)加载完成之后,才会继续执行其他代码,也就是会造成阻塞(因为引入一个文件则该文件内部的所有代码都会被执行一次)。
require是一个函数,可以帮助我们引入一个文件(模块)中导出的对象。
require(X)如何查找:
情况一:X是一个核心模块,比如path、http :
直接返回核心模块,然后停止查找。
情况二:X是以./
或../
或/(根目录)
开头的:在对应的目录下查找,
1.如果有后缀名,按照后缀名的格式查找对应的文件。
2.没有后缀名,查找文件X -> 找X.js -> 找X.json -> 找X.node
3.没有找到对应的文件,将X作为一个目录,查找X/index.js -> 找X/index.json -> 找X/index.node
情况三:直接是一个X(没有路径),并且X不是一个核心模块
会逐级查找上一层目录下的node_modules
如果都没找到,那么报错 not found
二、ES6模块化详解
ES Module是ES6推出的。 即es 2015
ES Module和 Commonjs的模块化有一些不同之处:
1.它使用了 Import和 export 关键字 ,不是模块也不是函数。
2.它采用编译期的静态分析,并且也加入了动态引用的方式
ES Module模块采用 export 和 import 关键字来实现模块化:
export负责将模块内的内容导出
import负责从其他模块导入内容
语法:
导入模块:import
导出模块:export
1、分别暴露
//在module1.js文件
// 分别暴露模块
export function foo() {
console.log('foo()');
}
export function bar() {
console.log('bar()');
}
export let arr = [1, 2, 3, 4, 5]
2、统一暴露
//在module2.js文件
// 统一暴露
function fun() {
console.log('fun()');
}
function fun2() {
console.log('fun2()');
}
export { fun, fun2 }
3、默认暴露
//在module3文件
// 默认暴露
export default {
msg: 'hello......',
fun: () => {
console.log('aaaaaaaaaaaaa');
}
}
引入模块
import {foo, bar} from './module1.js' // 如果是单个的js文件 引入时要加上后缀
import {fun, fun2} from './module2.js'
import module3 from './module3.js' //默认暴露
import $ from 'jquery' // 引入的是一个npm下载的包,就不需要加后缀
import express from 'express'
foo();
bar();
fun();
fun2();
console.log(module3.msg);;
console.log(module3.fun());
详解:
通常,我们把要导入的东西列在花括号 import {…} 中:
//在 main.js文件
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
但是如果有很多要导入的内容,可以使用 import * as 将所有内容导入为一个对象,例如:
// 在main.js文件
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
import * as写起来也很短,但是我们为什么要明确列出我们需要导入的内容?
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:
这里有几个原因。
1、现代的构建工具(webpack 和其他工具)将模块打包到一起并对其进行优化,以加快加载速度并删除未使用的代码。
比如说,我们向我们的项目里添加一个第三方库 say.js,它具有许多函数:
// 在say.js文件
export function sayHi() { ... }
export function sayBye() { ... }
export function becomeSilent() { ... }
现在,如果我们只在我们的项目里使用了 say.js 中的一个函数:
// 在main.js文件
import {sayHi} from './say.js';
那么,优化器(optimizer)就会检测到它,并从打包好的代码中删除那些未被使用的函数,从而使构建更小。
2、明确列出要导入的内容会使得名称较短:sayHi() 而不是 say.sayHi()。
3、导入的显式列表可以更好地概述代码结构:使用的内容和位置。它使得代码支持重构,并且重构起来更容易。
不用花括号的导入看起来很方便。刚开始使用模块时,一个常见的错误就是忘记写花括号。所以,import 命名的导出时需要花括号,而 import 默认的导出时不需要花括号。
import 函数
通过 Import加载的模块,是不可以在其放到逻辑代码中的,比如:
let flag = true
if (flag) {
// 错误用法,语法错误,不能在逻辑在逻辑代码中使用 import 关键字
import format from './modules/foo.js'
}
如何解决?使用 import()
函数 或者 require()
// 注意:上边使用import时是作为关键字使用,现在是作为函数使用,
// 该函数为异步函数,返回值为promise
let flag = true
if (flag) {
import('./modules/foo.js').then(res => {
console.log('then里边的回调');
console.log(res);
}, err => {
console.log(err);
})
}
设置工具库的统一出口:
在项目中经常有很多的工具函数,分散在不同的文件中,如果要引入的话,需要找到对应的文件来引入,每次都去找对应的文件比较麻烦,可以搞一个统一的出口,要用的话,直接导入这个出口文件就可以了。
/**
* 工具的统一出口
*/
// 1.导出方式一:挨个导入再挨个导出
import { sub, add } from './math.js'
import { timeFormat } from './format.js'
export { sub, add, timeFormat }
// 2.导出方式二:直接导出指定的
export { sub, add } from './math.js'
export { timeFormat } from './format.js'
// 3.导出方式三: 直接导出所有的
export * from './math.js'
export * from './format.js'