模块化开发
提高开发效率,降低维护成本,模块化本身只是一个思想,不包括具体的实现
模块化概述
模块化规范的出现
CommonJs规范
每个文件就是一个模块
每个模块都有一个单独的作用域
通过module.exports导出成员
通过require函数载入模块
同步的模式加载模块
node执行是在页面加载时加载模块
页面加载时导致大量的同步请求出现,导致效率低下
AMD
早期的浏览器使用规范,AMD:异步的模块定义规范
推出require.js库,是一个强大的模块加载器
define用来定义一个模块,默认接收两个参数,如果传三个参数的话
1、函数的名字,后续加载函数是使用
2、数组,用来生命模块的依赖项
3、函数的参数与数组一一对应,每个参数就是依赖项导出的成员,函数的作用是为当前的函数提供一个私有的空间,向外部导出一些成员通过return导出
提供require函数,用来自动加载模块,当require模块需要加载模块,自动去创建script标签去发送脚本文件请求,并且去执行相应的模块代码
绝大多数的第三方库都支持AMD规范
但是使用起来比较复杂,导致代码的复杂程度提高
模块js请求次数比较频繁,导致页面效率比较低下
define('module1', ['jquery', './module2'], function($, module2){
return {
start:function(){
$('body').animate({margin:'20px'})
module2()
}
}
}).
Sea.js+CMD(淘宝推出的)
//CMD规范类似于Commonjs规范
define(function(require, exports, module){
//通过require引入依赖
var $ = require('jquery')
module.export = function() {
console.log('module2')
$('body').append('<p>module2</p>')
}
}).
模块化标准实现
nodejs中引用commonjs的使用规范
通过module.exports导出模块,然后通过require导入
浏览器中引用ES Modules
Es Modules
ES Modules 特性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ES Modules 模块的特性</title>
</head>
<body>
<!-- 通过给script添加type = module的属性,就可以以ESModule的标准执行其中的js代码-->
<script type = "module">
console.log("this is ES module")
</script>
<!-- 1、采用严格模式,忽略'use strict',不能在严格模式使用this-->
<script type = "module">
console.log(this)//undefined
</script>
<!--2、运行在单独的私有作用域中-->
<script type = "module">
var foo = 100
console.log(foo)
</script>
<script type = "module">
console.log(foo)//undefined
</script>
<!--3、通过cors的方式请求外部js模块,src的请求地址的服务端必须要支持cors-->
<script type = "module" src="">
console.log(foo)//undefined
</script>
<!--script标签会延迟执行脚本,类似于defer-->
<script type = "module" src="demo.js">
console.log(foo)//undefined
</script>
</body>
</html>
ESmodule导出和导入
导出
---app.js
import {fooName, default as myHello} from './module.js'
console.log(fooName, myHello)
---module.js
var name = "myModule"
function hello() {
console.log('hello')
}
class Person{
}
export {
name as fooName,
//当as为default,导入进来时要修改为别名
hello as default,
Person}
export default name
导入和导出要注意的问题
---module.js
var name = "myModule"
var age =30
//改变的是name,age的引用关系
export { name, age}
//
// export default {name, age}
//相当于
// export default {name:name, age: age}
---app.js
import {name, age} from './module.js'
//name, age是只读的
name = 'tom'//报错
console.log(name, age)
导入
import {name, age} from './module.js'
//导入 utils/index.js Commonjs可以省略index.js
//但是EsModule不能省略,./也不能省略,也可以使用绝对路径,或者完整的url
import {lowcase } from './uils/index.js'
console.log(lowcase('111'))
//----执行这个模块而不是去提取模块js,记载这个模块,主要针对子功能模块
//import {} from './module.js'
//import './module.js'
//导入所有的引用
// import * as mod from './module.js'
// console.log(mod)
// if(true){
// //只能出现在最顶层,不能用于判断条件语句
// import {name } from './module.js'
// }
//动态加载模块
// import('./module.js').then(function(module){
// console.log(module)
// })
import {name, age, default as title } from './module.js'
//abc代表默认导出部分
import abc, {name, age} from './module.js'
console.log(abc, name, age)
浏览器环境polyfill
某些浏览器类似于IE不支持Es-module引入的script标签引入
可以引入unpkg.com下的对应文件路径,nomodule是为了防止支持Es-module的浏览器下加载下面的文件
node环境使用Es-module
将js文件转为mjs
启动时node --expermintal-modules index.mjs