闭包

##0 前置知识:
基于js的函数作用域,局部变量的特性,函数外部是无法访问函数内部的变量的。
而有时我们恰恰有这样的需求,这就有了闭包的方法。
##1 闭包的概念:
闭包是指可以访问另一函数内部变量的函数
通常构造闭包的方式是在函数中定义一个函数,用做访问函数内部变量的**“钩子”,或者可以理解为开辟了外部访问函数内部变量的“绿色通道”**。
##2 闭包的原理分析:

  function f1(){

    var n=999;

    function f2(){
      alert(n); // 999
    }
  }

遵循js作用域链的规则,上述代码中,f2可以访问f1的变量n。因此我们只需要将f2返回出来,就可以实现闭包。

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

我们发现,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收
另外,nAdd也是一个闭包,因此可以访问函数f1内的n,若是换成在函数外定义一个nAdd函数,浏览器会报错,无法访问到n。

result(); // 999
var nAdd = function() {
	n += 1
}
nAdd();

这里写图片描述

##3 闭包的优缺点:

1.通过闭包获取到的变量会永久的保留在内存中,不会被回收,因此闭包要慎用,否则会给浏览器带来较大的负担,影响性能。严重的会导致内存泄漏,解决方法是,在退出函数之前,将不使用的局部变量全部删除。

  1. 通过闭包访问的,函数内部的变量不再隐私,可以在函数外对其进行修改,因此在对闭包获取的变量进行操作时,不要随便更改其值。

##4 闭包的常见使用方法:
1.通过将函数return出去,使其可在外部访问。

function foo(){
    var a = 2;
    function bar(){
        console.log(a); //2
    }
    return bar;
}
foo()();

2 通过将其作为想要执行的函数的参数。

//在foo()函数的作用域中声明,在bar()函数的作用域中被调用的baz()函数是闭包
function foo(){
    var a = 2;
    function baz(){
        console.log(a); //2
    }
    bar(baz);
}
function bar(fn){
    fn();
}
foo() // 2

3 将内部函数赋值给一个外部变量

var inner;
var F = function(){
    var b = 'local';
    var N = function(){
        return b;
    };
    inner = N;
};
F();
console.log(inner());

##5 通过闭包嵌套解决常见的for循环i问题

function createFunctions(){
    var result = new Array();
	
	for(var i=0;i<10;i++){
		result[i] = function(){
			return i;
		};
	}
	return result;
}
console.log(createFunctions());

以上代码,for循环执行中,每次匿名函数调用完后,执行环境的作用域链被销毁,但是活动对象仍然保留。
因此,createFunction()函数会返回一个函数数组,每个元素都是一个函数指针,在调用执行时找i,此时i均为i=10。
通过闭包解决上述问题:

function createFunctions(){
    var result = new Array();
	
	for(var i=0;i<10;i++){
		result[i] = function(num){  //i将作为参数传进来,保存在作用域内,因此每个num都在不同的作用域中,通过闭包访问的值就是正常我们需要的。
			return function (){
				return num
			};
		}(i);
		//或者采用自执行函数解决
		//(function (){
		//  result[i] = i
		//})()
	}
	return result;
}
console.log(createFunctions());

##6 闭包实现私有变量封装
借助闭包,同样可以封装一个类,保留其私有变量。
在使用时不用担心交叉污染的问题!

function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}

var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13

在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。
参考文章:
闭包,阮一峰
JavaScript闭包

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值