模块化的理解
模块化的理解
1.什么是模块?
将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起
块的内部数据与实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信
2.为什么使用模块及模块化?
模块及模块化
以module.exports(暴露)和require(引入 )来说
(1):达到代码重用性,避免全局变量的污染
模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,
分别反映其内部特性。
模块化是一种处理复杂系统分解为更好的可管理模块的方式。
代码冗余度降低
模块化的进化过程
全局
* 全局function函数模式: 将不同的功能封装成不同的全局函数
-
问题: Global被污染了, 很容易引起命名冲突 Global:全局
namespace( 命名空间 )- namespace模式: 简单对象封装
- 作用: 减少了全局变量 解决命名冲突
- 问题: 不安全(数据不是私有的, 外部可以直接修改)
iife - IIFE模式: 匿名函数自调用(闭包) 立即执行函数 ()() (function(){}())
- IIFE : immediately-invoked function expression(立即调用函数表达式)
- 作用: 数据是私有的, 外部只能通过暴露的方法操作
*编码: 将数据和行为封装到一个函数内部, 通过给window添加属性来向外暴露接口 - 问题: 如果当前这个模块依赖另一个模块怎么办(顺序问题)?
iife增强(引入依赖)
- 现代模块实现的基石
-
引入多个
4.模块化的好处
避免命名冲突(减少命名空间污染)
更好的分离, 按需加载
更高复用性
高可维护性
每个模块都有特定的功能!
5.模块化规范
1.CommonJS
(1)概述
Node 应用由模块组成,采用 CommonJS 模块规范。
每个文件就是一个模块,有自己的作用域。
在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
在服务器端,
模块的加载是运行时同步加载的;在浏览器端,模块需要提前编译打包处理。
(2)特点
所有代码都运行在模块作用域,不会污染全局作用域。
模块可以多次加载,但是只会在第一次加载时运行一次,
然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。
要想让模块再次运行,必须清除缓存。
模块加载的顺序,按照其在代码中出现的顺序。
(3)基本语法
暴露模块:module.exports = value 和module.exports.name = value
和 exports.xxx = value
引入模块:require(xxx),
如果是第三方模块,xxx为模块名;
如果是自定义模块,xxx为模块文件路径./ ../
(4)模块的加载机制
CommonJS模块的加载机制是,require()输入的是被输出exports的值的拷贝。
也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
这点与ES6模块化有重大差异
(5)服务器端实现
(6)浏览器端实现(借助Browserify)
全局: npm install browserify -g
工具类 安装的路径
C:\Users\sam\AppData\Roaming\npm\包名
局部: npm install browserify --save -dev
-save 的意思是将模块安装到项目目录下,
并在package文件的dependencies(依赖)节点写入依赖。
-save-dev 的意思是将模块安装到项目目录下,
并在package文件的devDependencies(开发环境的依赖)节点写入依赖。
打包:browserify src/app.js > dist/bundle.js
(1)如果拿到别人的项目,需要安装之前package.json中
devdependencies 和 dependencies两个模块下所列举的依赖,可以通过执行以下命令实现
npm install
(2)如果拿到别人的项目,只需要安装之前package.json中
dependencies 模块下所列举的依赖,可以通过执行以下命令实现
npm install packagename
(3)如果拿到别人的项目,只需要安装之前package.json中
devdependencies 模块下所列举的依赖,可以通过执行以下命令实现
npm install packagename -dev
browserify打包的命令
语法是:
browserify 源文件路径>打包到新的文件路径
browserify src/app.js> dist/bundle.js
2.AMD Asynchronous Module Definition 异步模块定义 (了解 )
CommonJS规范加载模块是同步的,也就是说,
只有加载完成,才能执行后面的操作。
AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,
模块文件一般都已经存在于本地硬盘,所以加载起来比较快,
不用考虑非同步加载的方式,所以CommonJS规范比较适用服务器端。
但是,如果是浏览器环境,要从服务器端加载模块,
这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
此外AMD规范比CommonJS规范在浏览器端实现要来着早。
RequireJS是一个工具库,主要用于客户端的模块管理。它的模块管理遵守AMD规范,
RequireJS的基本思想是,通过define方法,将代码定义为模块;
通过require方法,实现代码的模块加载。
AMD模块定义的方法非常清晰,不会污染全局环境,
能够清楚地显示依赖关系。AMD模式可以用于浏览器环境,并且允许非同步加载模块,
也可以根据需要动态加载模块。
requirejs的网址
https://github.com/requirejs/requirejs.git
https://webscripts.softpedia.com/script/Development-Scripts-js/Other-Libraries/RequireJS-65561.html
3.CMD Common Module Definition 模块定义规范。 模块的基本书写格式和基本交互规则。(了解)
CMD规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。
CMD规范整合了CommonJS和AMD规范的特点。在 Sea.js 中,
所有 JavaScript 模块都遵循 CMD模块定义规范。
下载sea.js, 并引入
官网: http://seajs.org/
github : https://github.com/seajs/seajs
Sea.js 推崇一个模块一个文件,遵循统一的写法
define(id?, deps?, factory)
因为CMD推崇
一个文件一个模块,所以经常就用文件名作为模块id
CMD推崇依赖就近,所以一般不在define的参数中写依赖,在factory中写
factory是一个函数,有三个参数,function(require, exports, module)
require 是一个方法,接受 模块标识 作为唯一参数,用来获取其他模块提供的接口:require(id)
exports 是一个对象,用来向外提供模块接口
module 是一个对象,上面存储了与当前模块相关联的一些属性和方法
module.exports
4.ES6模块化(掌握)
ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,
以及输入和输出的变量。
CommonJS 和 AMD 模块,都只能在运行时确定这些东西。
比如,CommonJS 模块就是对象,输入时必须查找对象属性。
var obj = require() obj.
module.exports
(1)ES6模块化语法
export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
export:暴露模块 import:引入
html
<script type="module">
import {a,b,c} from "./a"
</script>
(2) ES6-Babel-Browserify使用教程
使用Babel将ES6编译为ES5代码,使用Browserify编译打包js。
第一步:npm init -y 初始化package.json文件
①定义package.json文件
②安装babel-cli, babel-preset-es2015和browserify
第二步:
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
npm install browserify --save-dev
preset 预设(将es6转换成es5的所有插件打包)
babel文档网址:
https://segmentfault.com/a/1190000008491089
第3步:创建.babelrc文件
③定义.babelrc文件
{
"presets": ["es2015"]
}
④定义模块代码
⑤ 编译并在index.html中引入
使用Babel将ES6编译为ES5代码(但包含CommonJS语法) :
babel Es6文件路径 -d Es5路径
第4步:
配置package.json文件
下scripts标签里面加入:
"dist": "babel src -d dist"
在cmd命令运行:
npm run dist 把src文件导入到dist文件下面
第5步:
使用Browserify编译js :
(2)browserify dist/app.js -o dist/bundel.js
第6步:
(3)index.html文件中引入bundle.js
–02ES6
-src
|-modlue1.js 模块1
|-module2.js 模块2
|-module3.js 模块3
|-main.js 入口函数 导入的module1 2 3
-dist 输出的目录
-.babelrc
-index.html html代码
-package.json
-package.lock.json
三、总结
CommonJS规范主要用于服务端编程,加载模块是同步的,这并不适合在浏览器环境,
因为同步意味着阻塞加载,浏览器资源是异步加载的,因此有了AMD CMD解决方案。
AMD规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。
不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅。
CMD规范与AMD规范很相似,都用于浏览器编程,依赖就近,延迟执行,
可以很容易在Node.js中运行。不过,依赖SPM 打包,模块的加载逻辑偏重
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,
完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。
加载的,因此有了AMD CMD解决方案。
AMD规范在浏览器环境中异步加载模块,而且可以并行加载多个模块。
不过,AMD规范开发成本高,代码的阅读和书写比较困难,模块定义方式的语义不顺畅。
CMD规范与AMD规范很相似,都用于浏览器编程,依赖就近,延迟执行,
可以很容易在Node.js中运行。不过,依赖SPM 打包,模块的加载逻辑偏重
ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,
完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。