js闭包理解

  • 内容
  • 评论
  • 相关

cbf79f974c09db8277401300a72707b2

什么是闭包:
当内部函数在定义它的作用域的外部被引用时,就创建了该内部函数的闭包 ,如果内部函数引用了位于外部函数的变量,当外部函数调用完毕后,这些变量在内存不会被释放,因为闭包需要它们.

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

使用闭包的好处?
保护闭包外函数内的变量安全。因为只有闭包才能使用。
在内存中维持一个变量,不随着外部函数执行完而销毁。(坏处也是好处)。

额外说说栈内存,栈内存:
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时,就在栈中为这个变量分配内存空间,当超过变量的作用域后,会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。栈有一个很重要的特殊性,就是存在栈中的数据可以共享。

先来看一段代码:

1.
function test(){
    var i=1;
}
alert(i);//必然会出现i is not defined的error

再来看一段代码:
2.
function test(){
var i=1;
    function inner(){
        var j=1;
    }
       return j;
}
alert(test());//同上一样必然也会出现j is not defined的error

为什么会出现这样的情况呢?其实很简单,第一段代码中的i是在函数test()内部定义的一个局部变量,并且没有在函数作用域内return i,而alert(i)则相当于alert一个全局变量i,而i在全局中又并未定义,根据js的函数作用域的不同,因此会出现i是未定义的;

第二段代码同理,变量j是子函数test()内定义的一个局部变量且没有return,因此在父函数return变量j时,j是未定义的,所以出现j未定义的错误。那么如何输出i和j?

下面修改1中的代码:

3.
function test(){
    i=1;
}
test();
alert(i);//输出1

或

function test(){
    var i=1;
return i;
}
alert(test());//输出1

这时候,由于函数test()内的i并没有使用var声明,因此i被定义为全局变量,在调用test()之后,i作为全局变量被赋值1.第二种情况,i有var声明,且函数test()有return i,因此在外部调用函数时会返回i的值.那么像上述代码2的情况,如何输出j?

下面修改2中的代码:

4.
function test(){
var i=1;
return function inner(){
var j=i;
return j;
}
}
alert(test()());//输出1

从修改的这段代码中可以看出来,子函数inner中可以引用父函数test中的变量i的值,而对比上面的代码2中可以发现,父函数test却不能引用子函数inner中的变量。这就是所谓的js作用域链,inner->test->window,内在变量的优先级inner>test>window。

理清了js函数及其作用域的一些概念之后,我们开始从代码中看一下闭包的特征了。下面先写一个普通的函数:

5.
function test(){
var i=1;
i++;
return i;
}
console.log(test());//输出2
//再次console.log
console.log(test());//仍然输出2

这说明了函数构造函数test()在每次执行完毕之后,其内部变量都会被销毁。

下面修改代码4:

6.
function test(){
var i=1;
var j;
function inner(){
j=i++;
return j;
}
return inner;
}
var a=test();
alert(a());//输出1
alert(a());//输出2

上面代码6是一个闭包,什么是闭包?简单来说就是“当test()内部函数inner()被外部变量a引用的时候,就创建了一个闭包”。那么从代码6中与代码5对比,就可以看出闭包的特征了:

1.保护闭包外函数内的变量安全。只有闭包才能使用。
2.在内存中维持一个变量,不随着外部函数执行完而销毁。(变量j不断递增)。

评论

8条评论
  1. Gravatar 头像

    gamefly

    Thanks very interesting blog!