javascript深入理解系列文章网址
https://www.jianshu.com/p/451eed9094f5
闭包真是面试80%会问到的问题
闭包的概念
简单来说能够读取其他函数内部变量的函数
怎么来理解这句话呢,我们都知道函数内可以读取外部的变量,但是函数外无法读取函数内部的变量
那么怎么才能做到读取函数内部的变量呢,我们可以在函数内部再定义一个函数,用这个函数读取函数内部的变量,然后最后返回里面这个函数执行的结果,我们就可以得到函数内部的变量了
function Out(){
var a=678;
function In(){
console.log(a);
}
return In;
}
var result=Out();
result();//678
那么闭包有什么用呢
1.可以读取函数内部的变量
2.让这些变量的值始终保持在内存中,不会在调用后被自动清除。
那我们什么时候用到闭包的?
1、通过闭包来封装私有方法
学过java的同学都知道,java可以在类里面写私有变量和方法,外面无法调用,其实在js里面也能实现的,怎么实现那就需要闭包了
var fn=(function(){
var counter=0;
function getValue(val){
counter+=val;
}
return {
increment:function(){
getValue(1);
},
decrement:function(){
getValue(-1);
},
value:function(){
return counter;
}
}
})();
console.log(fn.value());//输出0
fn.increment();
console.log(fn.value());//输出1
学过java的同学看到这个是不是很熟悉,像不像java里的面向对象,这里面的increment,decrement,value就相当于闭包,我们可以封装私有变量counter,然后通过闭包对齐操作
解决循环错误的问题
我们先来看代码
<body>
<button>0</button>
<button>1</button>
<button>2</button>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
for(var i=0;i<$("button").length;i++){
$("button").eq(i).click(function(){
console.log(i);//输出结果总是3
});
}
</script>
上面我们定义了三个按钮,原计划点击相应的按钮,打印相应的文字,但是我们像如上的写法输出后每次的结果都是3,为什么呢,因为我们定义的这些函数不是立即执行函数,而是点击的时候才会执行,可是当我们点击的时候,循环已经结束,i为3,所以我们输出的值都为3。如何解决呢,这就要使用闭包了
<body>
<button>1</button>
<button>2</button>
<button>3</button>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
for(var i=0;i<$("button").length;i++){
(function(val){
$("button").eq(val).click(function(){
console.log(val);
});
})(i);
}
</script>
当for循环的时候,自执行函数就会执行
$("button").eq(val).click(function(){
console.log(val);
});
而val值是从外面传过来,里面的闭包就会记住每一次的值,存在内存中,每一次的
$("button").eq(val).click(function(){
console.log(val);
});
都是互相独立的,所以每一次输出的值互不相同
let和闭包的关系
同样是这个问题
<body>
<button>0</button>
<button>1</button>
<button>2</button>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
for(var i=0;i<$("button").length;i++){
$("button").eq(i).click(function(){
console.log(i);//输出结果总是3
});
}
</script>
之所以输出结果总是为3,是因为js只有全局作用域和函数级作用域,当点击的时候就会调用全局作用域i,i为3,所以我们可以使用es6的语法let去添加块级作用域
<body>
<button>0</button>
<button>1</button>
<button>2</button>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
for(let i=0;i<$("button").length;i++){
$("button").eq(i).click(function(){
console.log(i);
});
}
</script>
只要把var改成let就可以,就有了块级作用域,每次点击button的时候都访问其内部的i变量,也就可以解决上面的问题
闭包的优缺点
优点:加强封装性,可以达到对变量的保护作用
缺点:1由于闭包内部变量优先级高于外部变量,所以多查找作用域链中的一个层次,就会在一定程度上影响查找速度
2.内存的浪费
如何避免浪费使父级函数=null;
参考
https://juejin.im/post/5aa90e5ef265da239f0713a1#heading-5
网友评论