js模块化规范浅析

491 阅读3分钟

前言

将所有的代码都写在一个文件或者模块里面,代码之间耦合性太强,任何修改都可能造成全局的污染,不利于后期的维护;并且同一个文件内功能不容易划分清晰,很难实现相同功能模块的重复利用。
js模块化是将一个复杂的程序按照一定的规范封装成几个独立的模块,再将这几个模块组合在一起完成复杂程序的功能。模块内部的数据和方法是私有的,只是向外部暴露一些方法与外部的其他模块进行通信。
主要浅析比较常用的三种模块化规范:commonjs、AMD(Asynchronous Module Definition)和es6,至于不常用的CMD(Common Module Definition)、UMD(Universal Module Definition)不在本文赘述。

commonjs

遵循commonjs规范的程序,每一个文件都可以当做是一个模块。模块在服务端运行时是同步加载的,在浏览器端无法直接运行,需要提前编译打包成浏览器能识别的规范。nodejs是遵循commonjs规范的实现。
1. commonjs运行环境
服务端:nodejs
浏览器:无法在浏览器直接运行,需要借助打包工具打包成浏览器能识别的规范。

2. commonjs示例

commonjs规范通过以下两种方式对外暴露模块:
(1)module.exports = value
(2)exports.xxx = value
exports默认为一个空对象。
通过require引入使用模块:
let module = require('./module')
代码结构:

1.png
module1.js

module.exports = {
    arr: [1, 2, 3],
    func: ()=>{
        console.log('module1')
    }
}

module2.js

exports.arr = [1, 2, 3]
exports.func = ()=>{
    console.log('module2')
}

main.js

let module1 = require('./module1')
let module2 = require('./module2')

console.log(module1.arr)
module1.func()

console.log(module2.arr)
module2.func()

在node环境中运行main.js,输出为:

[ 1, 2, 3 ]
module1
[ 1, 2, 3 ]
module2 

commonjs运行在浏览器
遵循commonjs规范的代码不能直接在浏览器中运行,如下示例: 添加index.html文件,引用main.js,index.html为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>commonjs</title>
</head>
<body>
    <script src="./main.js"></script>
</body>
</html>

在浏览器打开以后,提示:

1.png
在浏览器运行之前,需要将遵循commonjs的代码编译打包成浏览器能识别的代码,这里使用browserify包(browserify.org/) 进行编辑打包:
本地安装browserify
npm install browserify --save-d
对main.js进行打包
browserify ./main.js -o ../dist/bundle.js
index.html引入打包以后的文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>commonjs</title>
</head>
<body>
<!--    <script src="./main.js"></script>-->
<script src="../dist/bundle.js"></script>
</body>
</html>

浏览器正常运行输出:

1.png

AMD

AMD(Asynchronous Module Definition) 异步模块定义,主要用于浏览器端。
1. AMD运行环境
在浏览器端运行。
2. AMD示例
AMD定义暴露模块:
(1)定义没有依赖的模块:

define(function(){
    return 模块
})

(2)定义有依赖的模块:

define(['module1', 'module2'], function(m1, m2){
    return 模块
})

AMD使用模块:

require(['module1', 'module2'], function(m1, m2){
    m1
    m2
})

AMD运行需要下载requirejs,下载地址为:requirejs.org/docs/downlo…
目录结构:

1.png
module1.js文件内容为

define(function(){
    return 'module1'
})

module2.js文件内容为

define(['module1'], function(m1) {
    return m1 + '+module2'
})

main.js文件内容为:

requirejs.config({
    paths: {
        module1: './module/module1',
        module2: './module/module2',
    }
})

requirejs(['module1', 'module2'], function(m1, m2) {
    console.log(m1)
    console.log(m2)
})

index.html文件内容为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>commonjs</title>
</head>
<body>
    <script data-main="./main.js" src="./libs/require.js"></script>
</body>
</html>

在浏览器打开index.html,输出

1.png

ES6

ECMAScript 6.0(简称 ES6)是 js 语言的下一代标准,在 2015 年 6 月发布第一个版本,一般提到ES6,都是指的ES2015标准。以后每年的6月份都发布一个新的版本,以年份作为标记,例如ES2015、ES2016等等。
1. ES6运行环境
ES6是针对js的规范,能运行js的环境就是ES6的运行环境。可能有些运行环境还不支持ES6的最新特性,所以一般是使用Babel 转码器(babeljs.io/) 将ES6代码转为ES5代码,然后在浏览器运行。
2. ES6示例
导出模块:export / export default
引入模块:import
目录结构:

1.png

module1.js文件

let fn1 = function func1() {
    console.log('module1')
}
export {fn1}

module2.js文件

let fn2 = function func2() {
    console.log('module2')
}
export default fn2

main.js文件内容

import {fn1} from './module/module1.js'
import fn2 from "./module/module2.js"
fn1()
fn2()

index.html文件内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>commonjs</title>
</head>
<body>
    <script type="module" src="./main.js"></script>
</body>
</html>

需要注意的是,浏览器支持es6语法的import和export,但是在引入js文件的时候,需要标注为module类型
在浏览器打开index.html,输出

1.png