定义:闭包 当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的变量,且返回的这个函数在外部被执行 就产生了闭包.闭包是一个环境,具体指的就是外部函数–高阶函数。
说白了就是一个环境,能够读取其他函数内部的变量。
本质上,闭包是将函数内部和函数外部连接起来的桥梁。
用处:1.读取函数内部的变量;
2.这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除。
优点:1:变量长期驻扎在内存中;
2:避免全局变量的污染;
3:私有成员的存在 ;
特性:1:函数套函数;
2:内部函数可以直接使用外部函数的局部变量或参数;
3:变量或参数不会被垃圾回收机制回收 GC;
缺点:
常驻内存 会增大内存的使用量 使用不当会造成内存泄露,详解:
(1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
var counter = 10;
function add () {
var counter = 0;
return function () {
counter+=1;
alert(counter)
}
}
// var s = add();
// s()// 1
// s()// 2
// s()// 3
function fn () {
var num = 223;
var fn1 = function () {
console.log(num)
}
num++;
return fn1;
}
// var fn2 = fn()
// fn2()//224
// fn2()//224
// fn2()//224
// 用途:闭包解决索引值问题
oLi = document.getElementsByTagName("li");
for (var i = 0; i < oLi.length; i++) {
/*oLi[i].onclick = function (index) {
return function () {
console.log(index)//
}
}(i)*/
(
function (j) {
oLi[j].onclick = function () {
console.log(j)
}
}
)(i)
}
// 私有成员的存在
var aaa = (function () {
var a =1 ;
function bbb () {
a++;
console.log(a)
};
function ccc () {
a++;
console.log(a)
};
return {//json结构
b:bbb,
c:ccc
}
})()
// aaa.b()//2
// aaa.c()//3
// aaa.b()//4
// aaa.c()//5
// function aaa(a){
// var b = 5;
// function bbb(){
// a++;
// b++;
debugger 1:断点调试 2:打断点
// alert(a);
// alert(b);
// }
// return bbb;
// }
//
// var ccc = aaa(2);
//
// ccc();
// ccc();
// var count = (function(){
// var a = 0;
// function add(){
// a++;
// return a;
// }
//
// return add;
//
// })()
//
// count();
// count();
//
// var nowcount = count();
//
// alert(nowcount);
// 在实际开发中,闭包主要是用来封装变量,收敛权限 变量的管理方案
function isFirstLoad(){
var list=[];
return function(option){
if(list.indexOf(option)>=0){ //检测是否存在于现有数组中,有则说明已存在
console.log('已存在')
}else{
list.push(option);
console.log('首次传入'); //没有则返回true,并把这次的数据录入进去
}
console.log(list)
}
}
// var ifl=isFirstLoad();
// ifl("zhangsan");
// ifl("lisi");
// ifl("zhangsan");
// 外界想访问list变量,只能通过我定义的函数isFirstLoad来进行访问,
// 想访问list的外界只提供了isFirstLoad这一个接口。至于怎么操作list,
// 已经定义好了,外界能做的就只是使用函数,然后传几个不同的参数
var val=function(){
var that=this;
var variable={};
variable.varity=1;
var returnVal={};
this.isString=function(str){
try {
if (typeof str !== "string") {
throw "TypeErr";
}else{
return true;
}
} catch (e) {
if (e == "TypeErr") {
return false;
}
}
}
//读
returnVal.getter=function(str){
var isStr=that.isString(str);
if(isStr){
return variable[str];
}else{
console.error("input type must string!!!!!");
}
}
//写
returnVal.setter=function(key,value){
var isStr=that.isString(key);
if(isStr){
if(variable[key]==undefined){
eval(variable[key]);
}
variable[key]=value;
}else{
console.error("input type must string!!!!!");
}
}
return returnVal;
}
var val= val();//初始化方法
console.log(val.getter("varity"));// 1
val.setter("va222rity",3);//不存在重新添加并赋值
console.log(val.getter("va222rity")); // 3
// 闭包的一个实际的应用 不会发生误操作(读写已经分离)