模块的理解
1.将一个复杂的程序,依据一定的规则,拆分成单个文件,并最终组合在一起。
2.这些拆分的文件就是模块,模块内部的数据是私有的,只是向外部暴露一些方法与外部其他模块通信。
为什么要模块化?
- 降低复杂度,提高解耦性
- 避免命名冲突
- 更好的分离,按需加载
- 更高的复用性,更高的可维护性
现在流行的模块化规范有2种:CommonJS、ES6
CommonJS
CommonJS模块化的代码,既可以在服务器端(node)运行,也可以在浏览器端运行
- 在服务器端的模块化代码可以直接运行
- 在浏览器端的模块化代码要经过Browserify编译
- 暴露语法
- 第一种方式:
module.exports = value - 第二种方式:
exports.xxx = value
- 引入语法
- 引入第三方模块:
require(xxx),xxx为模块名 - 引入自定义模块:
require(xxx),xxx为模块文件路径
exports和module.exports指向一个对象
module.exports暴露
module1暴露:暴露出去的是一个对象
const data = '123'
const msg = 'abc'
module.exports = {
showData(){
console.log(data);
},
showMsg(){
console.log(msg);
}
}
使用:因为暴露的是一个对象,所以a就是一个对象,使用对象里面的数据:对象名.属性就可以使用
//const module1 = require('./module1')
//引用的同时,解构赋值
const {showData,showMsg} = require('./module1')
module1.showData();
module1.showMsg();
exports暴露 module2使用exports.xxx = value去暴露,value是暴露的内容,xxx是它的名字
exports.sum = function(a,b){}
exports.sub = function(a,b){}
使用
const module2 = require('./module2')
//引入的同时,解构赋值
const {sum,sub} = require('./module2')
引入的内容是什么,取决于暴露的是什么
如果module.exports和exports.xxx产生引入冲突,那么优先执行module.exports的。也就是说module.exports和exports.xxx不能混用!
引入第三方模块 先npm下载第三方模块,然后直接导入模块名,比如:
npm install uniq
const uniq = require('uniq')
上方所有的代码都是在node环境下运行的,都是在集成终端中:node app 命令来实现的
Commonjs浏览器端
CommonJS在浏览器端的模块化代码要经过Browserify编译。
比如说require()命令,就是node专有的命令,所以浏览器是执行不了这个命令的。
因此需要全局安装:npm i browserify -g
对引入后的最终模块进行Browserify编译:browserify _最终模块路径_ -o _指定路径_
-o:将编译后的最终模块,输出到指定模块,一般叫build.js
browserify ./app.js -o ./build.js
ES6模块化(用的最多)
ES6模块化规范是浏览器与服务器端通用的模块化开发规范。他的出现,极大地降低了前端开发者的模块化学习成本,开发者不再需要额外的学AMD、CMD、CommonJS等模块化规范。
- 每个js文件都是一个独立的模块
- 导入其他模块成员,使用import关键字
- 对外共享模块成员使用export关键字
通过npm init -y快速初始化一个包管理初始化配置文件:package.json
在package.json中:"type":module,使用ES6模块化语法。
默认导出与默认导入
默认导出:export default 默认导出的成员
//定义模块私有成员
let n1 = 10
function show(){}
//默认导出,使用export default语法,向外共享n1和show
export default {
n1,
show
}
默认导入:import 接收名称 from '模块标识符'
import m1 from './01.js'
console.log(m1)//{n1:10,show:[Fcuntion:show]}
默认导出与默认导入的注意事项
- 默认导出: 在每个模块中,【只允许使用唯一的一次】export default,否则会报错!!!
- 默认导入:
默认导入时的【接收名称】必须是合法的成员名称。不能以数字开头!!!
//不合法!因为123接收名称以数字开头了
import 123 from './01.js'
按需导出与按需导入
按需导出的语法:export 按需导出的成员
//当前模块为02.js
export let s1 = 'aaa'
export function say(){}
按需导入的语法:import {解构赋值} from '地址'
import {s1,say} from './02.js'
console.log(s1)//aaa
console.log(say)//一个方法
按需导出与按需导入的注意事项
- 每个模块中可以使用多次按需导出
- 按需导入的成员名称必须和按需导出的名称一致
- 按需导入时,可以用
as关键字进行重命名 - 按需导入可以和默认导入一起使用
按需导入的成员名称必须和按需导出的名称一致
export let s1 = 'aaa'
import {s1} from './02.js'
按需导入时,可以用
as关键字进行重命名
export let s1 = 'aaa'
import {s1 as str1} from './02.js'
console.log(str1)//s1已经没了,必须使用它的别名
按需导入与默认导入配合
export let s1 = 'aaa'
export function say(){}
let info = 'test'
export default{
info
}
import info,{s1,say} from '02.js'
直接导入并执行
如果只是单纯的执行某个模块中的代码,并不需要得到模块中向外共享的成员,此时可以直接导入(import)并执行模块代码。
//当前文件模块./03.js
for(let i = 0;i<3;i++){
console.log(i)
}
test.js
直接导入并执行模块代码,不需要得到模块向外共享的成员
import './03.js'