闭包的概念
函数执行形成一个私有作用域,保护里面的私有变量不受外界的干扰,这种保护机制叫做闭包。
一个简单的闭包:
var utils = (function(){
return {
}
})()
复制代码
闭包的作用
- 保护(保护私有作用域不受外界干扰)
- 保存(形成一个不销毁的私有作用域)
什么时候用到闭包
-
在团队开发过程中,我们通常会把自己的代码存放在一个私有作用域中,如果别人需要使用某些方法的话,可以通过return或者window.xxx暴露在全局下。
-
jQuery源码也是利用这种保护机制的
~function(){ var jQuery = function(){ } window.$=window.jQuery=jQuery }() 复制代码
-
闭包解决选项卡问题
<div class="tabBox" id="tabBox"> <ul> <li>标题1</li> <li>标题2</li> <li>标题3</li> </ul> <div class="selected">content1</div> <div>content2</div> <div>content3</div> </div> var tabBox = document.getElementById('tabBox'), oList = tabBox.getElementsByTagName('li'), oDivList = tabBox.getElementsByTagName('div'); function changeTab(index){ //index 存储当前点击li的索引 for(var i=0;i<oList.length;i++){ oList[i].className = oDivList[i].className = null //清除样式 } oList[i].className = oDivList[i].className = 'selected' } for(var i=0;i<oList.length;i++){ oList[i].onclick = function(){ //三次循环给三个li都绑定了一个方法,但是都没有执行,当循环结束了,i此时为3, //等到点击的时候,就无法实现想要的效果了 changeTab(index) } } 复制代码
解决办法是:
-
自定义属性方式(可以给当前元素加一个属性)
for(var i=0;i<oList.length;i++){ oList[i].myIndex = i; oList[i].onclick = function(){ changeTab(this.myIndex) } } 复制代码
-
闭包机制
for(var i=0;i<oList.length;i++){ oList[i].onclick = (function(i){ //执行自执行函数首先会形成一个私有作用域 //接下来 形参赋值 i=0,i=1,i=2 return function(){ changeTab(i) } })(i) } //形成不销毁的私有作用域,不一定要有return,我们也可以写成这样 for(var i=0;i<oList.length;i++){ (function(i){ oList[i].onclick = function(){ //oList[i].onclick占用了返回的function,所以这个作用域也不会被销毁 changeTab(i) } })(i) } 复制代码
现在有这样一道题
function fn(){
var i=1;
return function(n){
console.log(n + i++)
}
}
var f= fn()
f(10) // 11
fn()(10) //11
f(20) //22
fn()(20) //21
复制代码
首先我们考虑变量提升
function fn(){ //fn内部会形成一个私有作用域,在私有作用域内,会发生形参赋值和变量提升,在这里并没有形参传递,我们只考虑变量提升
var i=1;
return function(n){ //return 引用类型的值才会让私有作用域不销毁
console.log(n + i++) // 先把i=1赋值给结果,然后i自己再加1
}
}
var f;
f= fn() //把fn执行的返回结果赋值给f 实际上f是function(n){console.log(n + i++)}
f(10) //把fn执行的返回结果再执行,并且给它传递一个参数10
fn()(10)
f(20)
fn()(20)
复制代码
闭包与this问题
var num = 1,
obj = {
num:2,
fn:(function(num){
this.num*=2;
num+=2;
return function(){
this.num*=3;
num++;
console.log(num)
}
})(num)
}
var fn = obj.fn;
fn();
obj.fn();
console.log(num,obj.num)
复制代码