再次相逢,你好,闭包

闭包,最熟悉的陌生人,用久了框架层级的东西,对最该知道的内容产生了陌生感,不过没关系,再次认识你一下。话不多说,我要开始认识你了。
但是,再学习闭包之前,要先简单回顾一下IIFE,立即执行函数,全名:immediately invoked function expression。

IIFE

  1. 会创建新的作用域,作用域的变量不会与外界变量相互污染。
  2. IIFE也可以有自己的返回值。

闭包

大家很容易搜到的定义大概是这样的 “一个函数访问了它的外部变量,那么它就是一个闭包”。如果这样理解的话。那么在javascript中,任何一个function都是闭包了。其实说的也没错,但是就是初学者可能无法真正的理解闭包。

	代码一:
	function foo(x) {
	   	var tmp = 3;
	    function bar(y) {
	        alert(x + y + (++tmp));
	    }
	    bar(10);
	}
	foo(2)

上面就是一个函数访问了它的外部变量,那么它就是一个闭包,写出来的例子,显然和真正意义上的闭包不太像那么一回事。那么我们看下面的例子。

	代码二:
   function foo(x){
   		var tmp = 3;
   		return function (y) {
   			alert(x + y + (++tmp));
   		}
   }
   var bar = foo(2);
   bar(10);

代码一和代码二的结果都为16。但是代码二看起来更像是闭包,对比一下,不难知道,两者的区别就是在于是否包含 “return”。下面根据自己的理解大概总结一下。
需要注意的是,上面的“return”并不是必须的,这是这里用作对比更为明显。

理解

一个函数访问了它的外部变量,那么它就是一个闭包

一个函数访问了它的外部变量,但是当它的外部函数退出之后,外部函数的变量却没有退出,仍维持在内部函数内,那么在内部函数就维持了外部函数的局部数据,这样的现象为理解上的闭包现象。

代码二举例说明:
外部函数: foo
外部变量:x 和 tmp
内部函数:return 出去的匿名函数

	var bar = foo(2); 执行外部函数 foo,
	bar(); 此时执行bar,而外部函数已经完成并退出,但是在 bar函数内,仍然保存外部变量 x 和 tmp。

看到这里,相信大家已经对闭包有了大概的印象,那么闭包到底在程序中什么地方会用到呢?

实例

在构建对象模式时,通常会有私有变量,私有方法。但在javascript中并没有这一类的名词概念,但是闭包就可以模拟实现构造函数内部的私有变量跟私有方法。具体代码如下:

   	 var makeCounter = function() {
   		  var privateCounter = 0;
   		  function changeBy(val) {
   		    privateCounter += val;
   		  }
   		  return {
   		    increment: function() {
   		      changeBy(1);
   		    },
   		    decrement: function() {
   		      changeBy(-1);
   		    },
   		    value: function() {
   		      return privateCounter;
   		    }
   		  }  
    };

上面就是闭包的比较实用的例子,但是这样会有一个问题,就是很容易还导致内存泄漏,因为这样确实是将变量私有化了,但是却一直没有释放。(关于这部分内容,作为小白的我还需要深入学习,是从别的网站看到会有这样的问题,就拿出来作为标记)
如果在项目里面不能充分的利用闭包的好处,可以考虑更换原型的方式修改自己的代码

   function MyObject(name, message) {
   	  this.name = name.toString();
   	  this.message = message.toString();
   	}
   	MyObject.prototype.getName = function() {
   	  return this.name;
   	};
   	MyObject.prototype.getMessage = function() {
   	  return this.message;
   	};

关于闭包的实用性,目前也就是学到这些,接下来,就是处理无意之中形成闭包带来的“惊喜”

	var arr = [];
    for (var i=0;i<3;i++){
         arr[i] = function () {
           return i;
         };
    }
    for(var j =0 ;j < 3; j++){
    	console.log(arr[j]());	
    }

上面的结果是 3,3,3
和预期的 1,2,3 好像不太一样
原因:在arr里面的每一项的function中的 i 值,都是3.这是因为,在javascript中,没有块级作用域,所以即使 i 是在for循环里面被定义的,但是它仍然是全局变量,每次的加加操作,都会改变它的值,然而,在第二个for循环进入的时候,第一个for循环已经完成,此时 i==3;
解决上面的问题,就需要用到我们开头写到的IIFE,因为 IIFE会创建新的作用域,作用域的变量不会与外界变量相互污染。 所以,在第一个for中的每一个i 都是新的作用域内部的i,不会相互污染。具体代码如下:

	 var arr = [];
     for (var i=0;i<3;i++){
	      (function(n){
            arr[n] = function () {
             return n;
            }
          })(i)
     }
     for(var j =0 ;j < 3; j++){
     	console.log(arr[j]());	
	 }

此次认识的闭包就这么多了,程序届的小白一枚,初出茅庐,鼓励之上。以上全是个人学习的心得。如有错误,请多多指正。

参考网址如下:
MDN.
JS中的IIFE和闭包.
Javascript闭包——懂不懂由你,反正我是懂了.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值