导言
一、前端模块化
二、ES6的模块化实现
1. ES6的模块化的出现
ES5以及它之前的js是没有模块化的,如果要进行模块化操作,需要引入第三方的类库。随着技术的发展,前后端分离,前端的业务变的越来越复杂,终于在ES6中引入了模块化的操作。
2. ES6模块化基本用法
es6中,一个模块就是一个js文件,所以我们新建一个模块(js文件)
es6模块化中模块与外部的数据传输是依赖于export(发送)和import(接收)这两个关键字的,下面通过一个例子来理解它们的用法
在module1.js中:
export let name = 'aays';//发送name这个变量
创建一个外部文件index.js,并且码入:
import {name} from './module1.js'//接收name这个变量
console.log(name)//aays
上面是最基本的用法,如果要输出多个变量可以将这些变量包装成对象进行模块化输出:
//模块
let name = 'aays',age = 18
const sex = '男'
export {
name,
age,
sex
}
//外部
<script type="module">
import {name,age,sex} from './module1.js'
console.log(age)//18
</script>
如果你想给传输过来的变量重新命名(可用于防止暴露模块当中的变量名字或者简化变量名),可以通过as来进行操作,上述代码修改为:
//模块
let name = 'aays',age = 18
const sex = '男'
export {
name as myname,
age as myage,
sex as mysex
}
//外部
import {myname,myage,mysex} from './module1.js'
console.log(myage)//18
如果你不想将export过来的一一解构赋值,那么你可以使用*符号来直接获取整个模块,上述代码修改为
//模块
let name = 'aays',age = 18
const sex = '男'
export {
name,
age,
sex
}
//外部
import * as allmodule from './module1.js'
console.log(`${allmodule.name}今年${allmodule.age}岁
性别${allmodule.sex}`)//aays今年18岁 性别男
3. 默认导出与混合导出
一个模块只能有一个默认导出
对于默认导出,导入的名称可以和导出的名称不一致。
//模块
export default function(){
return "默认导出一个方法"
}
//外部
import fn from './module1.js'//fn可以是任意变量名
console.log(fn())//输出“默认导出一个方法”
//我们可以将要导出的东西都放在默认导出中,
//然后取出来作为一个对象直接取里面的东西来用,比较方便
混合导出即同时在一个export中导出默认数据与非默认数据,加个逗号就能实现
//模块
export default function(){
return "默认导出一个方法"
}
export let name ="aays";
//外部
import fn,{name} from "./module1.js";
console.log(fn()+name);//默认导出一个方法aays
4. 重命名export和import
如果导入的多个文件中,变量名字相同,即会产生命名冲突的问题,为了解决该问题,ES6为提供了重命名的方法,当你在导入名称时可以这样做:
export let myName="我来自module1.js";//模块1中
export let myName="我来自module2.js";//模块2中
//外部
import {myName as name1} from "./module1.js";
import {myName as name2} from "./module2.js";
console.log(name1);//我来自module1.js
console.log(name2);//我来自module2.js
三、ES6 之前如何实现模块
es6之前,js并没有模块。随着代码复杂度提升,开发者们为了应对难以维护的代码而考虑使用js现有的特性去实现模块化。
模块要求:
- 隐藏内部实现
- 提供调用接口
函数内部的变量是私有对外不可见的,借用该特点可以实现隐藏内部实现的需要。
function ff(){
var a=123;
var b="abcdef";
}
console.log(a)//错误,a未定义
利用函数的返回对象,通过 函数闭包特性(第五小节介绍)
,实现对内部数据对访问,间接实现了调用接口。
通过该接口,我们可以方便的使用模块内的功能,例如ffobj.f0();
// 闭包函数
function ff(){
var a=123;
var b="abcdef";
var f0 = function(){
console.log("a is :"+a);
}
return {a:a,b:b,f0:f0}
}
var ffobj = ff();
ffobj.f0()
简化定义与调用步骤,直接改为立即执行函数即可
const ffobj1 = function(){
var a=123;
var b="abcdef";
var f0 = function(){
console.log("a is :"+a);
}
return {a:a,b:b,f0:f0}
}();
四、commonjs的模块化
mathUtils.js
function add(num1, num2) {
return num1 + num2
}
function mul(num1, num2) {
return num1 * num2
}
module.exports = {
add,
mul
}
main.js 使用commonjs的模块化 导入 info.js
// 1.使用commonjs的模块化规范
const {add, mul} = require('./mathUtils.js')
console.log(add(20, 30));
console.log(mul(20, 30));
五、函数闭包
1. 定义:
闭包函数
:声明在一个函数中的函数,叫做闭包函数。闭包
:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
2. 解析:
闭包就是能够读取其他函数内部变量的函数。
3. 特点:
- 闭包外层是一个函数。
- 闭包内部都有函数。
- 闭包会return内部函数。
- 闭包返回的函数内部不能有return(因为这样就真的结束了)。
- 执行闭包后,闭包内部变量会存在,而闭包内部函数的内部变量不会存在。
4. 优点:
( 1 ) 可以有私变量的存在;
( 2 ) 避免全局变量的污染;
( 3 ) 希望一个变量长期驻扎在内存中,防止私有变量被垃圾回收机制所清除;
5. 缺点:
( 1 ) 闭包比普通函数占用更多的内存,会造成内存泄漏;在不使用时,要及时释放,将引用内层函数对象的变量赋值为null。