模块化
视频学习(讲的非常好): https://www.bilibili.com/video/BV18s411E7Tj/?spm_id_from=333.337.search-card.all.click
概述
概念
概念:
- 将一个复杂的程序序依据一定的规则(规范)封装成几个块(文件),并进行组合在一起
- 内部数据与实现是私有的,只是向外部暴露一些接口(方法)与外部其它模块通信
? ?
IIFE(Immediately Invoked Function Expression): 立即调用函数表达式;自执行匿名函数 == 其实就是闭包
(function (version) {
console.log('当前版本号:', version?version:'v1.0.0')
})('v1.1.1');
发展进程
发展1:全局function模块
- 全局function模块: 把不同的功能函数封装成不同的全局函数
function getName() {
}
function getYear() {
}
发展2:命名空间
? ? 2. 命名空间模块: 基于简单的对象封装
问题:数据不安全,外部可以直接修改内容模块的数据;所有模块成员直接暴露在外
let obj = {
name: '',
getName() {},
getYear() {}
}
obj.name = 'lrc'
发展3:IFFE:立即执行函数(闭包)- 绑定到window上
变量直接全部变私有
(function (win) {
let version = '1.1.0';
win.myUtils = {
getVersion() {
return version;
},
strIsNotEmpty(content) {
let result = content && content.length > 0;
if ((typeof result) === 'string') {
return result.length > 0;
} else {
return result ? true : false;
}
},
strIsEmpty(content) {
return !this.strIsNotEmpty(content);
}
}
})(window)
console.log(myUtils.getVersion())
console.log(myUtils.strIsEmpty(''))
发展4(现代):IFFE升级版直接返回对象不绑window变量上,外面由对象接收
let myUtils = (function (win) {
let version = '1.1.0';
return {
getVersion() {
return version;
},
strIsNotEmpty(content) {
let result = content && content.length > 0;
if ((typeof result) === 'string') {
return result.length > 0;
} else {
return result ? true : false;
}
},
strIsEmpty(content) {
return !this.strIsNotEmpty(content);
}
}
})()
console.log(myUtils.getVersion())
console.log(myUtils.strIsEmpty(''))
工具
本节源码: https://gitee.com/changenen/module-study
CommonJS规范 - (需使用工具编译打包)
概述
官网: https://commonjs.org/ ? 维基百科: https://wiki.commonjs.org/wiki/Modules/1.1 ? 特点: 需要编译打包后才能在浏览器使用
说明
1. 每个文件都可当作一个模块
2. 在服务器端:模块的加载是运行时同步加载的
3. 在浏览器端:模块需要提前编译打包处理
一个模块文件仅能写一次多写,后面会覆盖前面
一个模块文件能写多次
npm install 包名
基本语法
暴露模块
module.exports = 暴露的东西
exports.暴露的东西名字 = 暴露东西
引入模块
require(xxx)
第三方模块:模块名
自定义模块:模块文件路径
实现
服务端实现:nodejs(https://nodejs.org/en/)
浏览器端实现:browserify(https://browserify.org/)
规范实现(服务端):node
npm init
npm install 依赖包
? module1.js
module.exports = {
msg: 'module1',
foo: function () {
return this.msg;
},
}
? module2.js
module.exports = function () {
return 'module2'
}
? module3.js
exports.foo = function () {
return 'foo() module3 invoked'
}
exports.bar = function () {
return 'bar() module3 invoked'
}
? app.js
let module1 = require('./module/module1.js')
let module2 = require('./module/module2.js')
let module3 = require('./module/module3.js')
let uniqMethod = require('uniq/uniq.js')
let moduleFooResult = module1.foo();
console.log(moduleFooResult)
let module2Result = module2();
console.log(module2Result)
let module3FooResult = module3.foo()
console.log(module3FooResult)
let module3BarResult = module3.bar()
console.log(module3BarResult)
let uniqResult = uniqMethod([1,2,3,4,3,2])
console.log(uniqResult)
? ?
node app.js
规范实现(浏览器端):browserify
npm install -g browserify
npm reuqire语法的js文件名 -o 转换成功后前端可直接引用的js文件名
? module1.js
module.exports = {
msg: 'module1',
foo: function () {
return this.msg;
},
}
? module2.js
module.exports = function () {
return 'module2'
}
? module3.js
exports.foo = function () {
return 'foo() module3 invoked'
}
exports.bar = function () {
return 'bar() module3 invoked'
}
? app.js
let module1 = require('./module/module1.js')
let module2 = require('./module/module2.js')
let module3 = require('./module/module3.js')
let uniqMethod = require('uniq/uniq.js')
let moduleFooResult = module1.foo();
console.log(moduleFooResult)
let module2Result = module2();
console.log(module2Result)
let module3FooResult = module3.foo()
console.log(module3FooResult)
let module3BarResult = module3.bar()
console.log(module3BarResult)
let uniqResult = uniqMethod([1,2,3,4,3,2])
console.log(uniqResult)
? 文件转换
browserify js/src/app.js -o js/dist/bundle.js
? index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script src="js/dist/bundle.js"></script>
</html>
AMD规范 - (无需使用工具编译打包)
概述
AMD(Asynchronous Module Definition): 异步模块定义 ? 作用: 专门用于浏览器端,模块的异步加载 ? 文档:https://github.com/amdjs/amdjs-api/wiki/AMD ? 特点: 不需要编译打包方可直接在浏览器使用
无依赖的模块
有依赖的模块
基本语法
暴露模块
define(function(){ return 模块})
define(['module1','module2'],function(m1,m2){ reutrn 模块})
引入模块
require(['module1','module2'], function(m1,m2){})
规范实现(浏览器端):require.js
官网: https://requirejs.org/ ? Github: https://github.com/requirejs/requirejs
API
官网: https://requirejs.org/docs/api.html
?
? 定义模块(define)
define(function() {
return 当前模块暴露的模块东西
})
define(['依赖的模块名1','依赖的模块名2'], function(依赖的模块名1,依赖的模块名2) {
return 当前模块暴露的模块东西
})
define(['require','依赖的模块名1', '依赖的模块名2'], function(require) {
let moduleObj = require('依赖的模块名1')
let moduleObj2 = require('依赖的模块名2')
return 当前模块暴露的模块东西
})
define(function(require) {
let moduleObj = require('依赖的模块名1')
let moduleObj2 = require('依赖的模块名2')
return 当前模块暴露的模块东西
})
define(function(require) {
let moduleObj = require('依赖的模块名1')
let moduleObj2 = require('依赖的模块名2')
let exports
exports.模块暴露的东西名字 = 当前模块暴露的模块东西
})
requirejs.config({
paths: {
模块名1: '模块文件路径',
模块名2: '模块文件路径',
}
});
define("当前模块名", ['依赖的模块名1','依赖的模块名2'], function(依赖的模块名1,依赖的模块名2) {
return 当前模块暴露的模块东西
})
requirejs.config({
paths: {
当前模块名: '模块文件路径',
}
});
?
? 使用模块(require、requirejs)
(function (){
require.config({
paths: {
hasRelyModule: './module/hasRelyModule',
noRelyModule: './module/noRelyModule',
noRelyModuleObj: './module/noRelyModule',
hasNameModule: './module/hasNameModule',
}
});
require(["hasRelyModule", "hasNameModule"], function (hasRelyModule,hasNameModule) {
console.log(hasRelyModule.getCurrentModuleInfo())
console.log(hasNameModule.getInfo())
})
})();
?
? 加载定义非AMD规范暴露的包 ordinaryJs.js
var ordinaryJs = (function() {
let moudleName = "ordinaryJs"
let verison = "1.4.1"
return {
getMoudleInfo() {
return `${moudleName}:${verison}`
}
}
})()
? main.js
(function (){
require.config({
paths: {
notAmdSpecificationOrdinaryJs: './module/ordinaryJs'
},
shim: {
notAmdSpecificationOrdinaryJs: {
deps: [],
exports: "ordinaryJs"
},
}
});
require(['notAmdSpecificationOrdinaryJs'], function (notAmdSpecificationOrdinaryJs) {
console.log("")
console.log(notAmdSpecificationOrdinaryJs)
console.log(notAmdSpecificationOrdinaryJs.getMoudleInfo())
})
})();
? main.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script data-main="js/main.js" src="js/lib/require2.3.6.js"></script>
</head>
<body>
</body>
</html>
使用
noRelyModule.js
define(function () {
let version = 'v1.1.0'
let moduleName = 'noRelyModule'
function getModuleInfo() {
return `${moduleName}:${version}`
}
return {
getModuleInfo:getModuleInfo
}
})
? hasRelyModule.js
define(['noRelyModuleObj'], function (noRelyModuleObj) {
let version = 'v1.2.1';
let moduleName = 'hasRelyModule'
function getCurrentModuleInfo() {
return `${moduleName}:${version} === 使用到的依赖模块信息为:${noRelyModuleObj.getModuleInfo()}`
}
return {
getCurrentModuleInfo: getCurrentModuleInfo
}
})
? main.js
(function (){
requirejs.config({
paths: {
hasRelyModule: './module/hasRelyModule',
noRelyModule: './module/noRelyModule',
noRelyModuleObj: './module/noRelyModule',
}
});
requirejs(["hasRelyModule"], function (hasRelyModule) {
console.log(hasRelyModule.getCurrentModuleInfo())
})
})();
? index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script data-main="js/main.js" src="js/lib/require2.3.6.js"></script>
</head>
<body>
</body>
</html>
CMD规范(Commonjs、AMD规范结合体) - (无需使用工具编译打包)
概念
CMD(Common Module Definition): 通用模块定义;模块需要时才会加载 ? 特点: 不需要编译打包方可直接在浏览器使用
无依赖的模块
有依赖的模块
基本语法
暴露模块
define(function(require, exports, module){ exports.xx = 暴露的东西;module.exports = 暴露的东西;})
define(function(require,exports,module){require('./module2');require.async('./module3',function(n){}),exports.xxx=value});
引入模块
define(function(require){var m1=require('./module1');var m4=require('./module4');m1.show();m4.show();})
define(function (require, exports, module) {
var module2 = require('./module2')
require.async('./module3',function(m3){})
exports.xxx = value
})
define(function(require){
var m1=require('./module1');
var m4=require('./module4');
m1.show();
m4.show();
})
规范实现(浏览器端):sea.js
官网: https://seajs.github.io/seajs/docs/#intro ? Github: https://github.com/seajs/seajs
使用
? module1.js
define(function(require,exports,module) {
let moduleName = "module1"
let version = '1.1.1'
exports.getModuleInfo = function () {
return `${moduleName}:${version}`
}
})
? module2.js
define(function(require,exports,module) {
let moduleName = "module2"
let version = '1.1.2'
module.exports = {
getModuleInfo: function () {
return `${moduleName}:${version}`
}
}
})
? module3.js
define(function(require,exports,module) {
let module1 = require('./module1')
let module2 = require('./module2')
let moduleName = "module1"
let version = '1.1.1'
exports.getModuleInfo = function () {
return `${moduleName}:${version} ===》 依赖${module1.getModuleInfo()}、${module2.getModuleInfo()}`
}
})
? main.js
define(function(require) {
let module3 = require('./module/module3')
console.log("")
console.log(module3)
console.log(module3.getModuleInfo())
let module2 = require.async('./module/module2', function (module2) {
console.log("")
console.log(module2)
console.log(module2.getModuleInfo())
})
})
? index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script src="./lib/sea.js"></script>
<body>
</body>
<script>
seajs.use("./main.js")
</script>
</html>
ES6规范(应用广泛、重要) - (需使用工具编译打包)
概念
文档: https://es6.ruanyifeng.com/#docs/module ? 特点: 需要编译打包后才能在浏览器使用
一个模块文件可写多次
一个模块文件仅能写一次
必须解构进行接收
基本语法
暴露模块
export
常规模块: export 函数定义/变量定义/对象定义
默认模块:export default 函数定义/对象定义
引入模块
import
常规模块、分别模块:import {} from '模块文件路径'
默认模块:import 自定义模块名 from '模块文件路径'
规范实现(浏览器端):Babel(转成ES5语法)、Browserify(编译打包成JS)
Babel官网: https://www.babeljs.cn/ ? 特点: 需要编译打包后才能在浏览器使用
npm init
npm install babel-cli browserify -g
npm install babel-preset-es2015 --save-dev
{
"presets": ["es2015"]
}
babel 源js文件目录 -d 转换后的文件输出目录
browserify .\js\es5\main.js -o .\js\dist\bundle.js
使用
? module1.js
export function foo1() {
console.log("module1:foo1 invoked")
}
export function bar1() {
console.log("module1:bar1 invoked")
}
export let info = 'module1'
? module2.js
function foo2() {
console.log("module1:foo invoked")
}
function bar2() {
console.log("module1:foo2 invoked")
}
let info = 'module2'
export {
info,
foo2,
bar2
}
? module3.js
export default () => {
console.log("module3的箭头函数被调用")
}
? module4.js
export default {
moduleName: 'module3',
version: 'v1.1.0',
getModuleInfo: function () {
return `${this.moduleName}:${this.version}`
}
}
? main.js
import {foo1,bar1} from './module/module1'
import { foo2,bar2,info } from './module/module2'
import module3Content from './module/module3'
import module4Content from './module/module4'
console.log("")
foo1()
bar1()
console.log("")
foo2();
bar2();
console.log(info)
console.log("")
module3Content();
console.log("")
console.log(module4Content.getModuleInfo())
? 开始语法转换以及打包编译浏览器可运行的js文件
# 语法转换
babel .\js\src\ -d .\js\es5
# 打包编译
browserify .\js\es5\main.js -o .\js\dist\bundle.js
? index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="js/dist/bundle.js"></script>
</body>
</html>
|