Javascript-关于闭包的理解

在了解闭包之前我们可能还需要了解变量的作用域、IIFE立即执行函数表达式

目录

1.变量作用域

1.1 全局作用域

1.2 局部作用域

1.3 块级作用域

2. IIFE立即执行函数表达式

2.1 什么是IIFE?

2.2 IIFE的作用

2.3 IIFE和特点

2.4 IIFE语法

2.5 IIFE的用法

3. 闭包

3.1 什么是闭包

3.2 闭包的作用

3.3 闭包的特点

3.3 闭包的缺点

3.5 闭包的写法

3.6 例子

4. 内存管理(解决闭包引起的内存泄露)


1.变量作用域


1.1 全局作用域

在函数外部定义的变量或函数,叫全局变量或全局函数。它们可以在当前程序的任意位置使用。在全局中定义变量可以用var,也可以直接添加window的属性。

生命周期:它们会一直占用内存,只能在当前文件中使用。如果想在多个文件中使用变量,需要用到cookie或本地存储。

1.2 局部作用域

在函数内部定义的变量或函数,叫局部变量或局部函数。它们只能在函数内部使用。在函数内部用var定义局部变量,如果用window定义的变量,则为全局变量。

生命周期:从调用时开始创建,到函数执行完后立即销毁。

1.3 块级作用域

在ES5中没有块级作用域,ES6中有。一对{}为一个块,块级作用域就是变量或函数只在当前这组{}中有效。在ES5中可以用IIFE实现块级作用域,ES6中用let实现。

 

2. IIFE立即执行函数表达式


2.1 什么是IIFE?

声明函数的同时立即执行调用这个函数。

定义的函数没有函数名,只能执行一次,无法在其它地方被调用,也不会造成全局污染。

2.2 IIFE的作用

可以用于解决运算中产生的全局污染问题(实际上它是一个闭包的写法)。

它也是ES5中实现块级作用域的方式。

2.3 IIFE和特点

1)将所有运算代码都放在匿名函数中;

2)函数是一个表达式,没有函数名,只能被执行一次;

3)执行一次后所产生的数据和变量就立即销毁,不会造成全局污染。

 

2.4 IIFE语法

(function(params){
。。。
})(params) 
//将函数的定义和调用写在一起

 

2.5 IIFE的用法

 (function(n) {
        sum=0;
        for (var i = 0; i<=n; i++) {
            sum+=i;
        }  
        window.yy=sum;
    })(100)
    console.log(yy);

 

var re=(function(n) {
        sum=0;
        for (var i = 0; i<=n; i++) {
            sum+=i;
        }  
        return sum;
    })(10)
    console.log(re);

 

3. 闭包

3.1 什么是闭包

闭包就是一种作用域的体现,函数外部可以访问函数内部 的数据。正常情况下,函数外部不能访问函数内部的变量,但是通过这种特殊的写法,将函数内的子函数暴露在全局上,可以在外部调用且可以访问到函数内部的数据,即可以让全局访问局部的数据

3.2 闭包的作用

  • 实现函数外部可以访问函数内部数据的功能
  • 减少了全局变量的使用,避免全局变量的污染

3.3 闭包的特点

  • 闭包一定是函数内嵌套函数
  • 闭包是一种作用域的体现,函数可以访问函数内的数据
  • 闭包通常采用IIIFE写法,由于内部数据被全局所调用,将延缓资源的回收(即闭包中的变量的值用完后不会立即销毁,回驻留一段时间)。

3.3 闭包的缺点

  • 闭包种的变量会占用更多的内存空间
  • 可能会导致内存泄露

3.5 闭包的写法

(function(){
...
window.函数名=function(){
    ...
    return 变量;
}
})()

 

 

 

(function(){
...
  return  function(){
    ...
    return 变量;
}
})()

3.6 例子

需求:循环延时输出结果 0 1 2 3 4

每次for循环将i的值传给闭包函数,当for执行完后,执行回调时,这时i的每一个值仍驻留在内存中

for (var index = 0; index < 5; index++) {
        (function (index) {
            setTimeout(function () {
                console.log(index);
            },10);
        })(index);
    }

 

 

 

4. 内存管理(解决闭包引起的内存泄露)

在闭包中调用局部变量,会导致这个局部变量无法及时销毁,相当于全局变量一样会一直占用着内存。如果需要回收这些变量占用的内存,可以手动变量设置为null,然而在使用闭包的过程中,比较容易形成JavaScript对象和DOM对象的循环引用,就有可能造成内存泄露。这是因为浏览器的垃圾回收机制种,如果两个对象之间形成了循环引用,那么他们都无法被回收

 

 (function () {
        var tt=document.getElementById('tt');
        tt.onclick=function(){
            console.log(tt.innerHTML);

        }
    })();

在上面的例子中,出现函数间的嵌套形成了闭包,变量tt是JavaScript对象,引用了id为tt的DOM对象,DOM对象的onclick属性又引起了闭包,而闭包又可以调用tt,因此形成了循环引用,导致两个对象都无法被回收。。。

 

要解决此问题,只需要把循环引用中的变量设置为null即可

 (function () {
        var tt=document.getElementById('tt');
        tt.onclick=function(){
            console.log(this.innerHTML);
        }
        tt=null;
    })();

 

如果在 func 函数中不使用匿名函数创建闭包,而是通过引用一个外部函数,也不会出现循环引用的问题。

 

  (function () {
        var tt=document.getElementById('tt');
        tt.onclick=test;
    })();
    function test() {
        console.log('node.js');
    }

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值