闭包
闭包可以理解为:告诉浏览器这些变量我还要用,不可以进行垃圾回收。
为什么需要闭包
我们先不强硬背八股文,看下面的代码
function foo(){
var a = 1;
console.log(a); // 1
}
console.log(a); // 报错
最后的打印会报错,我们不能使用到foo中的a。因为作用域不同,那如果我们想访问foo中的a,应该怎么办?
什么是闭包
function foo(){
var a = 1;
return a;
};
const a = foo();
console.log(a); // 1
这样我们就可以访问到foo中的a了。
浏览器的内存空间是有限的,所以函数内的局部变量,会在函数执行时创建,执行完成时会销毁。如果不希望它销毁,就要让外部的变量保持对局部变量的引用。例:上述代码中全局中的a,就保持了对foo中a的引用,是的foo中的a不会被销毁。
强大的闭包
封装模块
在写项目时,如果所有的变量都定义在全局作用域,会导致内存消耗过大、变量名容易重复等问题。闭包的存在,让我们可以把项目分割成功能块,每个功能都有自己的作用域。这样代码规划更清晰,复用性更高。
看这个例子: 做了一个班级信息的模块,暴露出add,del,getInfo,可以增加学生、减少学生、获取学生信息。
- info存储所有信息;
- add向info中加入数据;
- del删除info中对应的数据;
- getInfo获取全班的信息;
const classInfo = (function() {
let info = [];
function add(name, age) {
info.push({
name,
age,
})
}
function del(name) {
info = info.filter(i => i.name !== name)
return info;
}
function getInfo() {
return info;
}
return {
add,
del,
getInfo
}
})()
console.log(classInfo.getInfo()) // []
classInfo.add('xiaohong', 18)
classInfo.add('xiaoming', 28)
classInfo.add('xiaowang', 38)
console.log(classInfo.getInfo()) // [{}, {}, {}]
classInfo.del('xiaowang')
console.log(classInfo.getInfo()) // [{}, {}]
模块化的实践
模块化是指多个模块之间相互协作。 我们先声明几个模块:
储存name模块
const allName = function (){
const names = [];
function add(name) {
names.push(name);
}
function getNames() {
return names;
}
return {
add,
getNames
}
}
储存age模块
const allAge = function (){
const ages = [];
function add(age) {
ages.push(age);
}
function getAges() {
return ages;
}
return {
add,
getAges
}
}
整合name和age信息的模块
const getNameAge = function(names, ages) {
function getNameAge() {
const nameArr = names.getNames();
const ageArr = ages.getAges();
const data = [];
for (let i = 0; i < nameArr.length; i++) {
data.push({
name: nameArr[i],
age: ageArr[i],
});
}
return data;
}
return {
getNameAge
}
};
模块组合
- module.define注册模块,注册时。如果使用到了其他模块,会作为参数传进去。
- module.get获取模块。
const module = (function () {
const modules = {};
function define(key, dep, impo) {
const args = [];
for (let key of dep) {
if (modules[key]) {
args.push(modules[key])
}
}
modules[key] = impo.apply(null, args)
}
function get(key) {
return modules[key];
}
return {
define,
get
}
})()
注册和获取
module.define('names', [], allName);
module.define('ages', [], allAge);
module.define('getNameAge', ['names', 'ages'], getNameAge);
const impoName = module.get('names');
const impoAge = module.get('ages');
const impoGetNameAge = module.get('getNameAge');
验证结果
新增数据,然后打印,观察数据是否正确。这样就实现了多模块之间的联合使用。
impoName.add('xiaoma');
impoAge.add(18);
impoName.add('xiaowang');
impoAge.add(20);
impoName.add('xiaoli');
impoAge.add(22);
console.log(impoGetNameAge.getNameAge())
总结
模块化对于开发十分重要,闭包是实现模块化的关键技术。作为js初学者必须对其有深刻的理解。