闭包js

闭包
概念:是指有权访问另一个函数作用域中的变量的函数。
1.它的本质是什么

实际上就是一种函数,该函数描述了:函数访问变量时其作用域的问题。
怎么判断他是不是一个闭包呢?
闭包的表现形式(满足以下形式就是闭包):
使函数外部能够调用函数内部定义的变量。就形成了一个闭包。说复杂点就是当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。

2.他产生的历史背景是什么?

2.1javaScript大环境下遵循以下规则:
函数内部可以读取函数外部的全局变量;
在函数外部无法读取函数内的局部变量。
2.2 javaScript的GC机制
在javaScript中,如果一个对象不再被引用,那么这个对象就会被GC回收,否则就会一直保存在内存中。
2.3为什么要使用闭包:
因为JS中变量的作用域分为全局变量和局部变量。在函数外部无法读取函数内的局部变量。需要闭包来解决。
2.4解决了什么问题:
描述:实现在函数外部可以读取函数内的局部变量,就出现了闭包。让函数执行完成后,内部的函数、变量还能被调用,可以采用闭包延长局部变量/函数的生命周期。
2.5使用场景:
排他、函数节流、网络…

3、闭包的作用:

1.使得在函数外部可以读取函数内的局部变量。
2.让这些变量的值始终保持在内存中

4、带来了什么问题:

滥用闭包,会造成内存泄漏;由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量指向null。
问题:想要访问内部函数的变量 name

Q:我想要在函数外部访问函数内部的变量

 function test() {
    	var age = "18";
    }
    console.log(age)//无法访问

solve:
最简单的一个闭包形式

/* 仔细阅读这段文字其实就是 简单描述了以下代码的文字描述,有没有
	当一个函数的返回值是另外一个函数,
	而返回的那个函数如果调用了其父函数内部的其它变量,
	如果返回的这个函数在外部被执行,就产生了闭包。
*/
function test() {
    var age = 18; // 局部变量
    return function () {
        console.log(age);
    }
}
var func = test();//将这个函数赋值给变量func
console.log(func);
/*
    ƒ () {
        console.log(age);
    }  
*/
func();//18  调用这个函数
/*
让函数执行完成后,内部的函数、变量还能被调用,
延长局部变量/函数的生命周期。达到在外界间接使用局部变量。
换句话说:使得在函数外部可以读取函数内的局部变量  */

闭包的使用场景:
1、 封闭作用域
(即使使用相同变量名称,都不会互相影响)
最大作用:全局变量私有化
优点:
不污染全局空间
内部所有的临时变量执行完毕都会释放不占内存。
可以保存全局数据
更新复杂变量

 (funtion(){})();
 	 ;(funtion(){})();
	+(funtion(){})();
	-(funtion(){})();
	?(funtion(){})();
(function () {
       var age = 18;
       console.log(age);//18
   })();

   (function () {
       var age = 25;
       console.log(age);//25
   })();

2、作用域链
嵌套之间的函数会形成作用域链,每次对作用域的访问实际上都是对整条域链的遍历查找,先查找最近的作用域,然后再查找全局作用域,如果在某个作用域中找到了变量就停止查找。如下:

var num = 3;
     (function () {
         (function () {
             (function () {
                 var num = 2;
                 (function () {
                     var age = 18;
                     console.log(num);//18
                 })();
             })();
         })();
     })();

3、闭包解决性能优化问题

(function () {
        var d = document;
        //性能做了一个优化document就是找了一次
        var btn = d.getElementById("btn");
        var btn1 = d.getElementById("btn");
        var btn2 = d.getElementById("btn");
        var btn3 = d.getElementById("btn");
        var btn4 = d.getElementById("btn");
    })();
     var num = 0;
    for(var k in window){
        num++;
      //document的对象有很多,每次去查找耗费很多性能
        document.write(num + "," + k + "<br/>")
    }
    //更加精简的做法 传参传到了全局就把document保存下来了
    (function (document) {
        var btn = document.getElementById("btn");
        var btn1 = document.getElementById("btn");
        var btn2 = document.getElementById("btn");
        var btn3 = document.getElementById("btn");
        var btn4 = document.getElementById("btn");
    })(document);

4、闭包解决高级排他思想

//有20个li标签
    var allLis = document.getElementsByTagName("li");
    var lastOne = 0;//标记当前选中标签
    for (var i = 0; i < allLis.length; i++) {
        (function (index) {
            allLis[index].onmouseover = function () {
                // 清除  之前选中的current类
                allLis[lastOne].className = "";
                // 设置
                this.className = "current";
                // 赋值 将lastOne赋值给当前的index
                lastOne = index;
            }
        })(i);
        //i是外界传进来的,里面的index
        //与外界的i保持同步
    }

5、闭包的参数传递

要实现向左右走


function move(speed) {
       var num = 0;
       return function () {
           num += speed;
           this.style.marginLeft = num + 'px';
       }
   }

   var lImg = document.getElementById("l");
   var rImg = document.getElementById("r");

   lImg.onmousedown = move(-50);
   rImg.onmousedown = move(50);

6.、函数节流

比如在调用onresize()这个函数的时候,就会触发这个函数非常频繁,造成用户体验度不好。因此出现函数节流

 var timer = null;
    window.onresize = function () {
        console.log(document.documentElement.clientWidth);
    }

函数节流就是 加个定时器 让其触发变缓慢点

  var timer = null;
    window.onresize = function () {
        clearTimeout(timer);
        timer = setTimeout(function () {
            console.log(document.documentElement.clientWidth);
        }, 400);
    }

用闭包改变后的节流函数

function throttle(fn, delay) {
        var timer = null;
        return function () {
            clearTimeout(timer);
            timer = setTimeout(fn, delay);
        }
    }
 window.onresize = throttle(function () {
        console.log(document.documentElement.clientWidth);
    }, 400);

以下代码实例帮助理解:

<script type="text/javascript">
	 function a(){
	 var o=1;  	
	 function b(){
       console.log(o++);
 	}
	b();
 }
 console.log(a())//打印出来是1
 console.log(a())//打印出来还是1
 console.log(a())//打印出来也是1

//理由:因为每次调用a()中的变量都会释放,所以每次都是打印出来的是1
//问题来了:我们要怎样实现调用a()中的变量进行累加。实现变量不释放。
//解决方案:想办法让a函数调用一次不释放变量,b函数调用多次,就能实现o的累加;
//改变代码:闭包登场:
定义和用法:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。

    function a(){
             	var o=1;
        	function b(){
                 console.log(o++);
               	}
               	return b;
         }
 var c=a();
 console.log(c());//打印出1
 console.log(c());//打印出2
 console.log(c());//打印出3

//a()是返回的是b()这个函数;将a()这个函数赋值给c;类似把b()托 管给c;这样多次调用C的同时可以看成是多次调用了b()这个函数。
总结:(以上说了那么多废话只是帮助理解)
因为在函数外部无法读取函数内的局部变量。使用闭包使得在函 数外部可以读取函数内的局部变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值