在学习js的过程中,很多小伙伴都有一些比较难理解的知识点,在这里我想说一下其中一个比较难理解的知识点——闭包。
有人问你:什么是闭包?一般的回答可能是这样的:一个函数嵌套一个函数。这个回答只能说是答出了闭包的一个比较明显的特点,确实从表面上看是这样
function outer(){ //外层函数
return function inner(){
//内层函数
}
}
但是,我们为什么要在一个函数的内部再写一个函数呢?原因是这样的我们在进行函数封装的时候,会把用到的变量放入函数中,成为一个局部变量,这个时候如果我们想使用这个局部变量只能在函数内部使用,如果在函数外部使用是会出现错误的。
function outer(){
var count = 0; //在函数内部创建的变量为局部变量
}
console.log(count) //Uncaught ReferenceError: count is not defined
/* 在全局下无法访问局部变量count */
那么我们确实想要使用函数内部的变量怎么办呢?可以通过return的方式把局部变量返回出来就可以,这种就形成了闭包环境。如下面的代码:
function outer(){
var count = 0; //局部变量
return function inner(){ //内层函数
console.log(count)
}
}
var inner = outer(); //outer执行过后会把return的返回值赋值给inner
console.log(inner);
/* ƒ inner(){ //内层函数
console.log(count)
} */
inner();
所以,闭包应该有两个特点:
- 函数里面有一些需要在函数外部使用的变量
- 通过return将这些变量返回出来
平常我们也会用到,比如在网页中有一个ul,ul里面包含了很多li,我们点击li的时候想要获取li的下标,这个时候就会出现一些问题
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
var oList = document.getElementById('list');
var oLi = oList.getElementsByTagName('li');
for(var i = 0;i < oLi.length;i++){
oLi[i].onclick = function(){
console.log(i)
}
}
在这里我们不管点击哪一个li会发现打印出来的都是10,想要点击li打印出当前的下标,我们就可以使用闭包来实现,实现方式如下:
var oList = document.getElementById('list');
var oLi = oList.getElementsByTagName('li');
for(var i = 0;i < oLi.length;i++){
(function(i){ //匿名函数
oLi[i].onclick = function(){
console.log(i)
}
})(i)
}
其实在这里想要获取对应下标,除了闭包还有其他方式大家可以下去看一看。闭包可以解决我们在外部访问不到内部变量的问题,但同时也存在一些弊端就是内存泄露,所以在使用闭包的时候一定要注意。