闭包

深入理解闭包

闭包的概念

函数执行形成一个私有作用域,保护里面的私有变量不受外界的干扰,这种保护机制叫做闭包。

一个简单的闭包:

var utils = (function(){
    return {
        
    }
})()
复制代码
闭包的作用
  • 保护(保护私有作用域不受外界干扰)
  • 保存(形成一个不销毁的私有作用域)

什么时候用到闭包

  1. 在团队开发过程中,我们通常会把自己的代码存放在一个私有作用域中,如果别人需要使用某些方法的话,可以通过return或者window.xxx暴露在全局下。

  2. jQuery源码也是利用这种保护机制的

     ~function(){
         var jQuery = function(){
             
         }
         window.$=window.jQuery=jQuery
     }()
    复制代码
  3. 闭包解决选项卡问题

         <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)
             }
         }
    复制代码

解决办法是:

  1. 自定义属性方式(可以给当前元素加一个属性)

     for(var i=0;i<oList.length;i++){
         oList[i].myIndex = i;
         oList[i].onclick = function(){
             changeTab(this.myIndex)
         }
     }
    复制代码
  2. 闭包机制

     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)
复制代码

函数执行返回了一个引用数据类型堆内存的地址(并且堆内存隶属于这个作用域),在外面有一个变量接收了这个返回值,此时当前作用域就不能销毁(想要销毁,只需要让外面的变量赋值为null)

闭包与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)
复制代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值