深入理解闭包

闭包之前一直都在看,却总感觉没有深入理解,一直处于云里雾里,今天终于可以炫耀的说我懂了!

闭包是什么?

官方解释我就不说了,只说我理解的吧~

闭包是提供给外部访问函数内部私有变量的一个接口

一个函数里定义另一个函数就会产生闭包

解释一下:

function func() {
    var a = 10;
    return function() {
        return a;
    };
}
var b = func();
console.log(b());

在函数里定义变量都是私有的,外面无法访问到函数内部,那么,就可以通过闭包,将私有变量返回,外界就可以访问到func函数里的变量了。所以,我说闭包是提供给外部访问函数内部私有变量的一个接口。

了解闭包的作用域链

此处已经在我的博客的上一篇深入理解作用域说过了,大家可以参考,这里就不再累赘。

闭包注意的几个小问题

我们来看几道题逐渐理解闭包

1.循环中的闭包

1>请注意第6行

 1 function func(list) {
 2     var arr = [];
 3     for(var i = 0; i < list.length; i++) {
 4         var index = i;
 5         arr.push(function(){
 6             console.log(‘index为‘ + index); //index
 7             console.log(‘list为‘ + list[i]);
 8         });
 9     }
10     return arr;
11 }
12 function output() {
13     var list = [1, 2, 3];
14     var all = func(list);
15     for(var i = 0; i < all.length; i++){
16         all[i]();
17     }
18 }
19 output();

结果为3个    index为2   list为undefined

2>请注意第6行

 1 function func(list) {
 2     var arr = [];
 3     for(var i = 0; i < list.length; i++) {
 4         var index = i;
 5         arr.push(function(){
 6             console.log(‘i为‘ + i);  //i
 7             console.log(‘list为‘ + list[i]);
 8         });
 9     }
10     return arr;
11 }
12 function output() {
13     var list = [1, 2, 3];
14     var all = func(list);
15     for(var i = 0; i < all.length; i++){
16         all[i]();
17     }
18 }
19 output();

结果为3个    i为3   list为undefined

结果是不是很出乎意料,之前我因为这个问题纠结了好长时间,只怪当初太年轻~~

在for循环中的使用闭包调用的是同一个闭包,因此无论for循环几次,都是最后一个值。那么,为什么是undefined呢?

这里不得不提到javascript中没有块级作用域,因此虽然看似是在for循环中声明了变量 i,但实际上i的作用域是func函数。并且闭包中局部变量是引用并不是

拷贝,因此,当退出循环时i为3,闭包中的i也就为3,list[3](list[2]为最后一个值)不存在,所以为undefined。

将上述第7行代码改为下面的代码

1 console.log(‘list为‘ + list[index]); //list[index]

将输出  list为3

index值自然是for循环中最后的一个i值为2。

解决办法

知道是什么原因了,那如何解决呢?

 1 function func(list) {
 2     var arr = [];
 3     for(var i = 0; i < list.length; i++) {
 4         var index = i;
 5         arr.push(
 6             (function(j){
 7             console.log(‘list为‘ + list[j]);
 8             })(i)
 9         );
10     }
11 }
12 func([1, 2, 3]);

输出  list为1  list为2  list为3

添加另一个闭包,并传参使其立即执行,参数是按值传递的,所以每一次传过去的值都是不同的值,得出我们想要的答案。

2.闭包中的this对象

 1 var num = 10;
 2 var obj = {
 3     num: ‘nana‘,
 4     getNum: function() {
 5         return function(){
 6             return console.log(this.num);
 7         }
 8     }
 9 }
10 obj.getNum()();

输出结果为:10

是不是又很神奇,在闭包中this是指向window的,所以,当我们访问this.a时,访问的是全局变量a。那么,想要访问函数func中的a呢?

解决办法

 1 var num = 10;
 2 var obj = {
 3     num: ‘nana‘,
 4     getNum: function() {
 5         var that = this;
 6         return function(){
 7             return console.log(that.num);
 8         }
 9     }
10 }
11 obj.getNum()();

输出结果为:nana

3.变量回收

1 function func() {
2     var a = 0;
3     return function(){
4         return ++a;
5     };
6 }
7 var f = func();
8 console.log(f());
9 console.log(f());

输出结果:1    2

在函数中的局部变量会随着函数执行完毕而被回收,可是,func函数引用着闭包函数,闭包中引用着局部变量a,因此,变量不会被js回收机制回收。第一次

调用f时a加1,第二次调用时,由于a未被回收,所以又在1的基础上又加了1为2。

那么,js中回收机制是怎么工作的呢?

在js中如果对象不再引用,则会被回收,如果两个对象互相引用不再被第三者引用也会被回收,但如果还被第三者引用就不会回收,上述由于处于这种情况所

以变量a不会被回收。

由于无法回收局部变量,会导致性能问题,因此,要避免滥用闭包,在闭包使用完毕时,需删除局部变量。

4.多个函数绑定同一闭包

 1 function func() {
 2     var num = 10;
 3     getNum = function() {
 4         console.log(num);
 5     };
 6     countNum = function() {
 7         num++;
 8     };
 9     setNum = function(x) {
10         num = x;
11     };
12 }
13 func();
14 getNum();
15 countNum();
16 getNum();
17 setNum(20);
18 getNum();

输出结果为10   11    20

5.闭包外部函数所有局部变量都在闭包内,声明在闭包函数后的局部变量也可访问

1 function func() {
2     function a(){
3         console.log(num);
4     };
5     var num = 10;
6     return a;
7 }
8 func()();

结果输出  10

6.函数调用时访问的是不同的闭包

 1 function func(list) {
 2     var arr = [];
 3     for(var i = 0; i < list.length; i++) {
 4         var index = i;
 5         arr.push(
 6             (function(j){
 7             console.log(list[j]);
 8             })(i)
 9         );
10     }
11 }
12
13 func([1, 2, 3]);
14 func([6, 7, 8]);

输出结果1,2,3   6,7,8

上面举了这么多例子,每个例子都不同,如果想完全理解的话只有当你遇到上述问题时,才会让你印象深刻,所以还是乖乖的去敲代码吧!

最后来个小测试

1 for(var i = 0; i < 5; i++) {
2     var index = i;
3     (function(j){
4         setTimeout(function(){
5             console.log(j);
6         },10);
7     })(i)
8 }

输出结果 0 1 2 3 4

1 for(var i = 0; i < 5; i++) {
2     var index = i;
3     (function(j){
4        setTimeout(function(){
5             console.log(index);
6         },10);
7     })(i)
8 }

输出结果 4 4 4 4 4

1 for(var i = 0; i < 5; i++) {
2     var index = i;
3     (function(j){
4         setTimeout(function(){
5             console.log(i);
6         },10);
7     })(i)
8 }

输出结果 5 5 5 5 5

猜对了么?如果没有,就再看看上面例子吧~

时间: 2024-11-08 20:41:47

深入理解闭包的相关文章

ES6之let(理解闭包)和const命令

ES6之let(理解闭包)和const命令 最近做项目的过程中,使用到了ES6,因为之前很少接触,所以使用起来还不够熟悉.因此购买了阮一峰老师的ES6标准入门,在此感谢阮一峰老师的著作. 我们知道,ECMAScript 6即ES6是ECMAScript的第五个版本,因为在2015年6月正式发布,所以又成为ECMAScript2015.ES6的主要目的是为了是JS用于编写复杂的大型应用程序,成为企业级的开发语言. 说明:由于有时候我们希望得知es6代码的具体实现原理或者说希望能够转化为es5使用,

JS 理解闭包

闭包是js的一个难点,许多高级应用都需要用闭包实现.要理解闭包,首先必须理解Javascript特殊的变量作用域,其次是垃圾回收机制. 一.理解变量作用域 ①  变量分为全局变量和局部变量,在函数内部可以直接读取全局变量,如: var a = 100; function x1(){ alert(a); } x1();  //得到 100 而在函数外部,自然无法读取函数内部的局部变量,如: function x1(){ var a = 100; } alert(a);//error ps:如果在函

javascript深入理解闭包

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

js深入理解&quot;闭包&quot;

一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量. Js代码 var n=999; function f1(){ alert(n); } f1(); // 999 另一方面,在函数外部自然无法读取函数内的局部变量. Js代码 function f1(){ var n=999; } alert(n); // error 这里有一个地方需要注意,函数

一步一步的理解闭包

一步步的理解闭包: javascript是函数作用域,按常理来说,一个函数就不能访问另一个函数中的变量. 而我们实际操作有时候需要用一个函数去操作另一个函数中的变量. 为了能够访问另一个函数作用域中的变量,javascript提供一种内部机制,给嵌套在其它函数中的函数提供了一种父作用域链保存机制. 当内部函数创建时,静态的保存了父作用域链,即使父函数执行完毕,其变量对象(这里面保存着我们想要的父变量)一直保存在内部函数的作用域链中.内部函数不再被调用之前,这个活动对象一直在内存中(通俗讲就是这时

JavaScript要理解闭包先了解词法作用域

之所以取名叫做词法作用域,是这个概念是js中相当基础也是极为重要的,很多想当然的错误或感觉怪异的问题都是和这个东西有关.所以,本文主要说下这个名词的概念以及讨论下他牵扯出来的有关变量.函数.闭包的问题. 由变量开始谈 习惯性先来段代码: view source print? 1 var x = "globol value"; 2 var getValue = function() 3 { 4     alert(x);    //弹出"undefined" 5   

JavaScript——以简单的方式理解闭包

闭包,在一开始接触JavaScript的时候就听说过.首先明确一点,它理解起来确实不复杂,而且它也非常好用.那我们去理解闭包之前,要有什么基础呢?我个人认为最重要的便是作用域(lexical scope),如果对作用域和作用域链不理解的同学最好自己先去学一学,再回过头来,理解闭包,就更加轻松. 下面便直接进入主题. 我们知道一个函数是有作用域的,在函数内部定义的局部变量只有在函数内部才可以访问的到.一旦函数访问结束被销毁,局部变量随之也会销毁,无法通过任何方式再次访问局部变量,除了闭包.也就是说

javascript深入理解 `闭包`

简单的例子: function house(){ var num=1;//房子内人的个数: addNum=function(){ //预留的增加函数人数的方法: num+=1; } function query(){//这个函数就叫闭包 alert(num); return num;//返回这个房子的人数 } return query;//返回查询这个房子人数方法的指针及地址: } var res=house();//将这个房子的查询方法的指针/地址赋给变量res; res();//查询房子里面

如何理解闭包?

1.定义: 嵌套在函数作用域中的函数,称为闭包函数.该作用域称为闭包环境.通过闭包函数可以访问闭包函数所在函数作用域中的形参与变量 2.表现形式: 使函数外部能够调用函数内部定义的变量 3.工作原理: 利用了js中的垃圾回收机制,当一个函数被调用时,开辟空间,函数调用结束,释放空间,垃圾回收机制释放被调用结束的函数时,发现函数的变量正在被其他的函数调用,这些变量不会被释放,而且被永久驻留在内存,只有退出程序,才会被释放,或者是手工释放(=null) 4.变量的作用域 要理解闭包,首先必须理解Ja