JavaScript 对闭包的理解 ★

目录

1、认识闭包函数

2、闭包的基本使用

3、定义闭包存储器

4、闭包的特性及优缺点


1、认识闭包函数

简单的说,闭包函数就是定义在一个函数内部的函数,它有权访问外部函数作用域中的变量。作为闭包的必要条件,内部函数应该访问外部函数中声明的私有变量、参数或其它内部函数。当上述的两个必要条件是实现后,如果在外部函数外调用这个内部函数,它就成为了闭包函数。比如下面这个经典的闭包结构。

function fun(x){         //外部函数
    var a = x;           //外部函数的局部变量。并把参数值传递给它
    var b = function(){    //内部函数
        return a;        //访问外部函数中的局部变量
    }
    a++;         //访问后,动态更新外部函数的变量
    return b;    //将内部函数作为外部函数的返回值
}
var result = fun(5); //调用外部函数,并赋值,这时会返回一个闭包
alert(result());     //调用内部函数,返回外部函数更新后的值6

简单描述,闭包可以说是函数的数据包,存储数据,这个数据包在函数执行过程中始终处于激活状态。当函数调用返回之后,闭包保存着与函数关联变量的动态联系。

补充:闭包并不一定是函数内部嵌套函数,还可以是函数内部嵌套对象,这个对象能操作外部函数中声明的私有变量或其他函数。这就是 jQuery 的封装思想,在获取元素后,返回的是一个能操作改元素的 api 对象,这也是一个闭包。

2、闭包的基本使用

(1)使用闭包结构能够动态跟踪其外部函数作用域中数据的变化,并即时存储。

function fun(){    //定义普通函数 fun
    var a = 1;     //定义局部变量a,初始值为1
    var b = function(){    //定义一个闭包,并赋值给局部变量b
        return a;    //返回函数参数中的局部变量a
    }
    a++;    //动态更新函数内局部变量a的值
    return b;    //返回闭包结构
}
var result = fun();    //调用函数
alert(result());       //返回2。而不是返回1

上面示例中,闭包中的变量 a,其存储的值并不是从上面一行变量 a 的简单赋值,而是继续引用外部函数定义的局部变量 a 中的值,所以闭包执行后返回 2,而不是返回 1。

(2)闭包不会因为外部函数环境的注销而消失,而是始终存在。

<button onclick="fun()">按钮1</button><br/>
<button onclick="b()">按钮2</button><br/>
<button onclick="c()">按钮3</button><br/>
<button onclick="d(100)">按钮4</button><br/>
<script language="javascript" type="text/javascript">
    function fun(){    //定义普通函数fun,包含多个闭包的外部环境
        var a = 1;     //定义函数内局部变量a,并设置初始值为1
        var b = function(){    //闭包b
            alert(a);      //寄存函数内局部变量a的值,并进行提示
        }
        var c = function(){    //闭包c
            a++;           //递增并寄存函数内局部变量a的值
        }
        var d = function(x){    //闭包d
            a = x;          //传递并寄存函数内局部变量a的值
        }
</scxipt>

在上面示例中,普通函数 fun 中定义了 3 个闭包函数,它们分别指向并寄存局部变量 a 的值,并根据不同的操作动态跟踪变量 a 的值。

当在浏览器中预览时,首先应该单击“按钮1”,调用函数 fun(),将生成 3 个闭包,并且 3 个闭包同时指向局部变量 a 的引用,因此当函数 fun() 返回时,3 个闭包函数都没有被注销,而变量 a 由于被闭包引用而继续存在。单击“按钮3”,则将动态递增变量 a 的值,此时如果单击“按钮2”,则会弹出提示值为 2。如果单击“按钮4”,则向变量 a 传递值 100,将动态改变闭包中寄存的值,此时如果单击“按钮2”,则会弹出提示值为 100。

(3)利用同一个闭包声明多个闭包。同一个闭包,通过分别引用,能够在当前环境中生成多个闭包。

function fun(x){    //定义普通函数
    var temp = x;
    return function(x){    //返回闭包
        temp += x;
        alert(temp);
    }
}

var a = fun(50);     //生成第1个闭包
var b = fun(100);    //生成第2个闭包
a(5);     //返回55
b(10);    //返回110

3、定义闭包存储器

闭包常见的用法就是为要执行的函数提供参数。例如,为定时器函数传递行为 setTimeout(fun,1000);  其中 fun 函数是不能带参数的,带了参数也是打印出 undefined。这个时候就需要使用闭包。这在 Web 前端中是非常常见的一种应用。

function fun(a,b){    //定义函数
    return function(){    //返回闭包函数
        a(b);
    }
}
var c = fun(alert,"Hello,World");    //调用函数 fun
var d = setTimeout (c,1000);    //把闭包作为参数进行传递

预定义函数 setTimeout() 用于有计划地执行一个函数,或者一串 JavaScript 脚本,要执行的函数是其第 1 个参数,第 2 个参数是以毫秒表示的执行间隔、也就是说,当在一段代码中使用 setTimeout() 函数时,需要将一个函数的引用作为它的第 1 个参数,而将以毫秒表示的时间值作为第 2 个参数。但是,传递函数引用的同时就无法调用函数。类似下面的用法是错误的:

function fun(a,b){    //定义函数
    a(b);
}
var c = fun(alert,"Hello,World");
var d = setTimeout (c,1000);     //返回第一个参数为非法的错误

然而,可以在代码中调用另外一个函数,由它返回一个对内部函数的引用,再把这个对内部函数对象的引用传递给 setTimeout() 函数。执行这个内部函数时要使用的参数在调用外部函数时进行传递,这样,setTimeout() 函数在执行内部函数时,不用再传递参数,但该内部函数仍然能够访问在调用外部函数时传递的参数。

再看一个示例,该示例演示了如何使用闭包作为值来进行传递。当文档加载完毕后,会自动弹出一个提示对话框。其中正是利用闭包来实现向 window 对象的 onload 属性传递一个闭包函数的,从而实现动态调用的效果。如下:

function fun(a,b){
    return function(){
        a(b);
    }
}
var c = fun(alert,"Hel1o,World");    //调用函数 fun
window.onload = c;    //把闭包作为值进行传递

4、闭包的特性及优缺点

(1)特性:

- 函数嵌套函数。- 函数内部可以引用外部的参数和变量。- 参数和变量不会被垃圾回收机制回收。

(2)优点:

- 希望一个变量长期存储在内存中。- 避免全局变量的污染。- 私有成员的存在。

(3)缺点:

- 常驻内存,增加内存使用量。- 使用不当会很容易造成内存泄露。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值