关于闭包的所有理解

闭包这家伙,从刚开始接触到javascript基础就走进我的脑子里,但是总感觉自己理解的不透彻,不清晰。然而,几乎每个面试官呢,又好像都挺喜欢问这个问题的,所有,没办法罗,只有再深入去探讨一下咯,哈哈。

1.什么是闭包

这里先给闭包下一个定义,简单概括为两点:

1).函数嵌套函数;

2).内层函数可以访问外层函数的变量和参数。

2.js中的垃圾回收机制

看代码说话:

 1         function aa() {
 2             a = 10;
 3         }
 4         aa();
 5         console.log(a); // 10  a没有var申明,默认是一个全局变量
 6         //上面代码等价于:
 7         var a;
 8         function aa(){
 9             a = 10;
10         }
11 
12 
13         // 对比下面这个例子:
14         function aa() {
15             var a = 10;
16         }
17         aa();
18         console.log(a);  //js中的垃圾回收机制  a is not defined

3.闭包的两个最大的用处

1).可以读取函数内部的变量

2).让这些变量的值始终保持在内存中(不会被垃圾回收机制所回收)

出于种种原因,我们有时候需要得到函数内的局部变量。但是,正常情况下,这是办不到的(js的垃圾回收机制),只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数。

 1         //example1:
 2         function f1() {
 3             var n = 999;
 4             nAdd = function () {
 5                 n += 1
 6             }; //全局变量
 7             function f2() {
 8                 alert(n);
 9             }
10 
11             return f2;
12         }
13          var result = f1();
14          result(); // 999
15          nAdd();
16          result(); // 1000
17         //这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,
18         // 首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。
19 
20         //example2:
21         (function (x) {
22             return (function (y) {
23                 console.log(x);
24             })(2)
25         })(1);
26         // result: 1  输出1,闭包能够访问外部作用域的变量或参数。

4.闭包只能取得包含函数中任何变量的最后一个值

看看下面这个闭包函数:

 1         function test1() {
 2             var result = [];
 3             for (var i = 0; i < 10; i++) {
 4                 result[i] = function () {
 5                     alert(i);
 6                 };
 7             }
 8             return result;
 9         }
10 
11         test1()[1](); // 10

执行任何一个test1()[i](); 结果都会弹出10.

5.我们可以通过创建另一个匿名函数强制让闭包的行为符合预期

 1     function test2() {
 2             var result = [];
 3             for (var i = 0; i < 10; i++) {
 4                 result[i] = function (num) {
 5                     return function () {
 6                         alert(num);
 7                     }
 8                 }(i);
 9                 //也可以这样写
10                 /*(function(m){
11                  result[m] = function(){
12                  alert(m);
13                  };
14                  })(i);*/
15             }
16             return result;
17         }
18         for (var i = 0; i < test2().length; i++) {
19             test2()[i](); // 0,1,2,3,...,8,9
20         }

这里用到了立即执行函数表达式。将 JavaScript 代码包含在一个函数块中有神马意思呢?为什么要这么做?句话说,为什么要用立即执行函数表达式(Immediately-Invoked Function Expression)。IIFE 有两个比较经典的使用场景,一是类似于在循环中定时输出数据项,二是类似于 JQuery/Node 的插件和模块开发。

 1         for (var i = 0; i < 5; i++) {
 2             setTimeout(function () {
 3                 console.log(i);
 4             }, 1000);
 5         }
 6         /*上面的输出并不是你以为的0,1,2,3,4,而输出的全部是5,这时 IIFE 就能有用了:*/
 7         for (var i = 0; i < 5; i++) {
 8             (function (m) {
 9                 setTimeout(function () {
10                     console.log(m);
11                 }, 1000);
12             })(i);
13         }
14         /* 输出 0,1,2,3,4 */
15         
16         /*而在 JQuery/Node 的插件和模块开发中,为避免变量污染,也是一个大大的 IIFE:*/
17         (function($){
18          //代码
19          })(jQuery);

6.闭包中关于this对象

 1         //example1:
 2         var name = "The Window";
 3         var object = {
 4             name: "My Object",
 5             getNameFunc: function () {
 6                 return function () {
 7                     return this.name;
 8                 };
 9             }
10         };
11         console.log(object.getNameFunc()()); // The Window 【匿名函数的执行环境具有全局性,this指向window】
12 
13         //example2: 改进
14         var name = "The Window";
15         var object = {
16             name: "My Object",
17             getNameFunc: function () {
18                 var that = this;
19                 return function () {
20                     return that.name;
21                 };
22             }
23         };
24         console.log(object.getNameFunc()()); // My Object
25 
26         //example3: 
27         var myObject = {
28             foo: "bar",
29             func: function () {
30                 var self = this;
31                 console.log("outer func:  this.foo = " + this.foo);
32                 console.log("outer func:  self.foo = " + self.foo);
33                 (function () {
34                     console.log("inner func:  this.foo = " + this.foo);
35                     console.log("inner func:  self.foo = " + self.foo);
36                 }());
37 
38                //用闭包来解决
39                 /*(function (test) {
40                     console.log("inner func:  this.foo = " + test.foo);  //'bar'
41                     console.log("inner func:  self.foo = " + self.foo);
42                 })(self);*/
43             }
44         };
45         myObject.func();
46         /*
47          * 输出结果:
48          outer func:  this.foo = bar
49          outer func:  self.foo = bar
50          inner func:  this.foo = undefined
51          inner func:  self.foo = bar
52          * */

 

posted @ 2017-01-19 16:19  芒果酱-Jessie  阅读(259)  评论(0编辑  收藏  举报