你不知道的JS---作用域和闭包

立即执行函数表达式

var a=2;
(function foo() {
	var a=3;
	console.log(a);
})();
console.log(a);

函数被包含在一个括号内部,因此成为了一个表达式,通过末尾加上另外一个括号可以立即执行这个函数。

闭包的定义
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。
循环和闭包
要想每隔1s输出数字1-5.
for(var i=1;i<=5;i++){
	setTimeout(function timer(){
		console.log(i);
	}, i*1000);
}
以每秒一次的频率输出五次6.
原因:延迟函数的回调会在循环结束时才执行,实际情况是 尽管循环中的五个函数是在各个迭代中分别定义的,但他们都被封闭在一个共享的全局作用域中,因此实际上只有一个i。

IIFE会通过声明并立即执行一个函数来创建作用域。
for(var i=1;i<=5;i++){
	(function(){
		setTimeout(function timer(){
			console.log(i);
		}, i*1000);
	})();
}
但是,通过上面的立即调用函数依然达不到效果,我们的IIFE只是一个什么都没有的空作用域,它需要有自己的变量,用来在每个迭代中储存i的值。
for(var i=1;i<=5;i++){
	(function(){
		var j=i;
		setTimeout(function timer(){
			console.log(j);
		}, j*1000);
	})();
}
对上述代码的改进:
for(var i=1;i<=5;i++){
	(function(j){
		setTimeout(function timer(){
			console.log(j);
		}, j*1000);
	})(i);
}
在迭代内使用IIFE会为每个迭代都生成一个新的作用域,使得延迟函数的回调可以将新的作用域封闭在每个迭代内部,每个迭代中都会含有一个具有正确值的变量供我们访问。
同样可以实现该功能的代码还有:
for(var i=1;i<=5;i++){
	let j=i;
	setTimeout(function timer(){
		console.log(j);
	}, j*1000);
}
for(let i=1;i<=5;i++){
	setTimeout(function timer(){
		console.log(i);
	}, i*1000);
}
变量的生命周期
var func=function () {
	var a=1;
	return function(){
		a++;
		alert(a);
	}
};
var f=func();
f();//2
f();//3
f();//4
f();//5

当退出函数后,局部变量并没有消失,这是因为当执行var f=func()时,f返回一个匿名函数的引用,可以访问到func()被调用时产生的环境,而局部变量a一直存在这个环境里。

闭包的使用场景

1、函数作为返回值
2、函数作为参数传递
function F1(){
	var a=100
	return function(){
		console.log(a)
	}
}
var f1=F1()
function F2(fn){
	var a=200
	fn()
}
F2(f1)//100

实际开发中闭包的应用

// 闭包实际应用中主要用于封装函数,收敛权限
function isFirstLoad(){
	var _list=[]
	return function(id){
		if(_list.indexOf(id)>=0){
			return false
		} else {
			_list.push(id)
			return true
		}
	}
}

// 使用
var firstLoad=isFirstLoad()
firstLoad(10)
firstLoad(10)
firstLoad(20)
1、封装变量
var mult=(function() {
	var cache={};
	return function(){
		var args=Array.prototype.join.call(arguments, ',');
		if(args in cache){
			return cache[args];
		}
		var a=1;
		for(var i=0,l=arguments.length;i<l;i++){
			a=a*arguments[i];
		}
		return cache[args]=a;
	}	
})();
2、延续局部变量的寿命
var report=function(src){
	var img=new Image();
	img.src=src;
};
report('http://xxx.com/getUserInfo')

var report=(function(){
	var imgs=[];
	return function(src){
		var img=new Image(src){
			var img=new Image();
			imgs.push(img);
			img.src=src;
		}
	}
})();



闭包的特性:

1、作为函数变量的一个引用,当函数返回时,其处于激活状态

2、闭包就是当一个函数返回时,并没有释放资源的栈区

闭包的原理:

因为闭包只有在被调用时才执行操作,所以它可以被用来定义控制结构,多个函数可以使用同一个相同的环境,这使得他们可通过改变那个环境相互交流

闭包使用场景:

1、采用函数引用方式的setTimeout调用

2、将函数关联到对象的实例方法

3、封装相关的功能

闭包的好处:

1、逻辑连续,当闭包作为另一个函数调用参数时,避免脱离当前逻辑二单独编写额外逻辑

2、方便调用上下文的局部变量。

3、加强封装,可以达到对变量的保护作用

闭包的坏处:浪费内存,闭包中的变量常驻内存,对闭包的使用不当会造成无效内存的产生。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值