js闭包

JavaScript变量分为全局变量和局部变量。局部变量可以用到闭包。

全局变量

函数可以访问函数内部定义的变量,例如:

function test{
    var a = 4;
    return a * a;
}

函数也可以访问外部定义的变量,例如:

var a = 4;
function test{
    return a * a;
}

结果均为 : 16
- 在第一个实例中,a 是一个局部变量。局部变量只能用于定义它的函数内部,对于其他的函数或脚本代码是不可用的。
- 在第二个实例中,a 是一个全局变量。在web页面中全局变量属于 window 对象。
- 全局变量和局部变量即便相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。

变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内部定义。

从外部读取局部变量

出于种种原因,我们有时候需要得到函数内的局部变量。但是,正常情况下是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数 :

function f1(){
    var n = 999;
    function f2(){
        alert(n);
    }
}

在上面的代码中,函数 f2 就被包括在函数 f1 内部,这时 f1 内部的所有局部变量,对 f2 都是可见的。但是反过来不行,f2 内部的局部变量,对 f1 就是不可见的。这就是js语言的“链式作用域”结构,子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然 f2 可以读取 f1 中的局部变量,那么只要把 f2 作为返回值,我们就可以在 f1 外部读取它的内部变量了。

function f1(){
    var n=999;
    function f2(){
        alert(n); 
    }
    return f2;
}
var result=f1();
result(); // 999

闭包

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

function f1() {
    var n = 999;
    nAdd = function () { n += 1 }
    function f2() {
        alert(n);
    }
    return f2;
}
var result = f1();
result(); // 999
nAdd();
result(); // 1000

在这段代码中,result 实际上就是闭包 f2 函数。它一共运行了两次,第一次的值是 999,第二次的值是1000。这证明了,函数 f1 中的局部变量 n 一直保存在内存中,并没有在 f1 调用后被自动清除。

为什么会这样呢?原因就在于 f1f2 的父函数,而 f2 被赋给了一个全局变量,这导致 f2 始终在内存中,而 f2 的存在依赖于 f1,因此f1 也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是 nAdd=function(){n+=1} 这一行,首先在 nAdd 前面没有使用 var 关键字,因此 nAdd 是一个全局变量,而不是局部变量。其次,nAdd 的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以 nAdd 相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。

例1

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>计数器</title>
</head>
<body>

<p>局部变量计数。</p>
<button type="button" onclick="myFunction()">计数!</button>
<p id="demo">0</p>
<script>
var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();
function myFunction(){
    document.getElementById("demo").innerHTML = add();
}
</script>

</body>
</html>

变量 add 指定了函数自我调用的返回字值。自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。add 变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。计数器受匿名函数的作用域保护,只能通过 add 方法修改。

例2

var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getNameFunc()());

通过 object.getNameFunc() 返回 function(){ return this.name; } 该匿名函数。但是这时候 this 指的是 window 全局对象,因此 this.name 指的是全局变量 var name = "The Window",所以输出的值为 The Window

例3

var name = "The Window";
var object = {
    name : "My Object",
    getNameFunc : function(){
        return function(){
            return this.name;
        };
    }
};
alert(object.getNameFunc()());

通过 object.getNameFunc() 返回 function(){ return this.name; } 该匿名函数。但是这时候 this 指的是 object 对象,因此 this.name 指的是局部变量 name : "My Object",所以输出的值为 My Object


参考自 :http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
http://www.runoob.com/js/js-function-closures.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值