一、闭包的定义
闭包:指得是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
二、闭包的特点
- 当产生了闭包的内部函数被返回并在其他地方被使用后,它仍引用着的外部函数的上下文!
- 产生了闭包的函数的作用域链包含外部函数的作用域。
三 、通过例子理解闭包
1、学生名单累加器
需求分析:
累加器 :包含名字name、学号number
添加学生:add
删除学生:reduce
打印名单:print
、解决方法之一
//其中:add reduce print均引用了外部的属性(i、allStus),均产生闭包
function students(){
// 共享属性
var allStus = [];
var i = 0;
function add(name){
// 每次函数调用的时候,重新生成 函数自身的AO(上下文)
// 所以这里的 cur 不会被覆盖
var cur = {};
cur.name = name;
cur.number = i + 1;
allStus.push(cur);
i++;
}
function reduce(name){
// 重名的情况下,一次只会删除一个且是前面那个
for(var j = 0 ;j < i;j++){
if(allStus[j].name === name){
allStus.splice(j,1);
i--;
break;
}
}
}
function print(){
// 打印数组
for(let j = 0 ;j < i;j++){
console.log(allStus[j]);
}
}
return [add,reduce,print];
}
var student = students();
student[0]('lily');
student[0]('jack');
student[0]('luky');
console.log('添加后的名单');
student[2]();
console.log('删除后的名单');
student[1]('lily');
student[2]();
结果:
、意料之外的方法()
唯一变化的是:把 cur 变量提到外部函数里,这也是我一开始的做法,因为想要有个公共对象存要被操作的学生对象信息
function students(){
// 共享属性
var allStus = [];
var i = 0;
var cur = {};
function add(name){
cur.name = name;
cur.number = i + 1;
allStus.push(cur);
i++;
}
function reduce(name){
// 重名的情况下,一次只会删除一个且是前面那个
for(var j = 0 ;j < i;j++){
if(allStus[j].name === name){
allStus.splice(j,1);
i--;
break;
}
}
}
function print(){
// 打印数组
for(let j = 0 ;j < i;j++){
console.log(allStus[j]);
}
}
return [add,reduce,print];
}
var student = students();
student[0]('lily');
student[0]('jack');
student[0]('luky');
console.log('添加后的名单');
student[2]();
console.log('删除后的名单');
student[1]('lily');
student[2]();
结果:(虾仁····)这里解释的话,我觉得关键影响因素有作用域链 跟 引用值类型
具体解释需要理解作用域链,,作用域链后期再解释。。
引用值类型在之前有文章解释了引用值类型解释