JS中的闭包

闭包问题是Javascript中的一个难点,也是它的一个特色,很多高级应用都需要闭包来实现,以下是我对闭包的一点点理解,希望对大家有帮助。

一、变量的作用域

在学习闭包之前,我们首先得理解JS变量的作用域
变量的作用域就是变量在某个范围内起到作用和效果,目的是为了提高程序的可靠性,当然更重要的是可以减少命名的冲突。
变量的作用域无非就是两种:全局变量和局部变量

JS的一个特殊之处在于函数内部可以直接读取全局变量

let num = 10;  // num 就是一个全局变量
function fn(){
	console.log(num); // 10
}
fn();

另一方面,在函数外部无法读取函数内部的局部变量

function fn(){
    let num = 10;
}
fn();
console.log(num); // 报错 num is not undefined

这里有几个需要注意的地方
(1)在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!

 function fn(){
     num = 10;
 }
 fn();
 console.log(num);  // 10 num 就是一个全局变量

(2)函数的形参也可以看作一个局部变量

function fn(num){
     console.log(num); // 10
}
fn(10);
console.log(num); // num is undefined

二、如何从外部读取局部变量

有时候,我们就是需要从外部用到函数里面的局部变量,很显然,用常规的方法是行不通的,我们可以在函数内部再定义一个函数

function fun() {
	var num = 10;
	function fn() {
	    console.log(num); // 10
	}
	fn();
}
fun();

通过上面我们可以看出,函数fn就被嵌入在函数fun的里面,这时fun所有的局部变量对fn是可见的,但是反过来就不行,fn内的局部变量对fun就不可见。既然fn可以读到外面fun的局部变量,那我们把fn当作返回值暴露出来不就可以实现在外部访问fun里面的局部变量了吗?

function fn1() {
	let a = 2;
	function fn2() {
	    a++;
	    console.log(a);
	}
	return fn2;
}
let f = fn1();
f(); // 3

三、闭包的概念

闭包就是能读取到其他函数内部变量的函数,我们也可以理解为包含引用变量的对象,它存在于嵌套的内部函数中,本质上闭包就是连接函数内部和函数外部的桥梁。
在这里我们也可以发现闭包产生的条件有两个:
(1)函数嵌套
(2)内部函数引用了外部函数的变量(函数)

四、闭包的用途

闭包可以用在很多地方,它最大的用途有两个,一个是前面说到的让函数外部可以操作到函数内部的变量;第二个是延长了变量的生命周期。我们都知道函数内部的变量(局部变量)在函数执行完后就会销毁,但使用了闭包后,就能让这个变量仍然存活在内存中。

五、闭包的生命周期

正如我们所理解的,生命周期就是从生到死的一个过程,我们需要知道闭包什么时候产生,什么时候死亡。

function fn1() {
	let a = 2;
	function fn2() {
	    a++;
	    console.log(a);
	}
	return fn2;
}
let f = fn1();
f = null;

1、闭包产生于内部嵌套函数定义完成时
也就是说在定义完上面的fn2函数就产生了,那闭包存在的关键是什么?
我们需要一个变量来接收内部的嵌套函数,让它在执行完毕后不会成为垃圾对象被回收,也就是上面的 let f = fn1(),用f接收fn1返回的fn2函数,目的就是让f保存fn2的内存地址,这样在执行完fn2后,即使fn2本身的栈内存被释放掉,fn2也不会成为垃圾对象被回收,因为仍有变量引用(保存)了它,从而维持了闭包的存在。
2、闭包死亡于包含闭包的对象成为垃圾对象时
执行完f函数后,将f赋值为null,使fn2成为一个空对象(垃圾对象),此时闭包死亡,如果在使用完闭包后不让闭包死亡,就有可能出现内存泄露的问题

六、常见的闭包

1、将函数作为另一个函数的返回值
2、将函数作为参数传递给另一个函数调用

function showDelay(msg,time){
	setTimeout(function(){
		alert(msg);
	},time)
}
showDelay('hx',2000);

3、(补充)如何判断产生闭包的个数?
只有调用了外部函数才会产生新的闭包,所以我们可以根据调用了几次外部函数就产生了几个闭包的方法来进行判断。

七、内存溢出与内存泄露

1、内存溢出:一种程序运行出现的错误,当程序运行需要的内存超过了剩余的内存时,就抛出内存溢出的错误。比如你运行某个程序需要100M的空间,但是系统只剩90M了,系统承受不了就报错,这就是内存溢出。
2、内存泄漏:占用的内存没有及时释放。就如我们上面的闭包,函数执行完后,函数内部的局部变量如果没有释放,占用内存的时间就会变长,为了避免内存泄漏,所以我们最后让f赋值为null。也就是说如果你申请了一块很大 的空间,自己只用一点,用完之后又不归还占用着,那别人也用不了。
常见的内存泄露有:
(1)意外的全局变量
(2)没有及时清理的定时器或回调函数
(3)闭包

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值