闭包问题

前言:基础知识点

  1.    js的作用域:在js中 函数内部可以读取函数外部变量,相反不可以。
  2.    作用域销毁:只是切断函数与AO(执行期上下文)的链接,并不是真实销毁AO的存在

总结:

  1. 闭包是什么:内部函数被保存到外部时,生成闭包
  2. 闭包缺点:闭包会导致原有作用域链不释放,造成内存泄漏
  3. 闭包用处:

实现公有变量 ;

实现缓存;

实现封装,属性私有化;

模块化开发,防止污染全局变量

闭包举栗子,如下

function fn(){
	var num = 100;
	function a(){
		num++;
		console.log(num);
	}
	return a
}
var myArr = fn();
myArr();

//打印结果为 101

上面栗子中,作用域以及执行期上下文时如何演变的?,以至于函数外部调用内部的值num呢?看下面

1.初始:
fn() defined  [[scope]] ——>0: GO {fn:function(){...},myArr:undefined}


2.var myArr = fn()执行时:
fn() doing    [[scope]] ——>0: fnAO  其中fnAO {num:100, a:function(){...} }
                           1: GO 略

a()  defined  [[scope]] ——>0: fnAO 略
                           1: GO 略
return a将 function a(){...}返回赋予全局变量myArr,结果 myArr=function a(){...}


3.var myArr = fn()执行完毕:
fn() 切断链接fnAO  [[scope]] ——>0: GO  
     但fnAO依旧存在,函数a仍有链接指向fnAO

4.myArr()执行时:  
a()  doing  [[scope]] ——>  0:aAO {}
                           1: fnAO  num=101
                           2: GO
 执行num++ ——> 作用域依次向下寻找num ——> 找到最近的fnAO中的num值 ,num++

上面过程解释了闭包是什么以及如果产生的,下面来看看再实际使用过程中会因为闭包造成的问题举栗:

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

for (var j = 0; j < 10; j++){
	m_demo[j]();
}

///打印结果为10个10,而非想象的0到9
1.初始:
demo() defined  [[scope]] ——>0: GO


2.var m_demo = demo()执行时:
demo() doing  [[scope]] ——>0: demoAO {arr:[function(){...},function(){...}...] ,i=10 }
                           1: GO

10个function()  defined  [[scope]] ——>0: demoAO 
                                      1: GO
return arr将 arr[...]返回赋予全局变量m_demo,结果 m_demo=arr[...]


3.var m_demo = demo()执行完毕:
demo() 切断链接demoAO  [[scope]] ——>0: GO  
     但demoAO依旧存在, m_demo[j]()有链接指向demoAO

m_demo[j]()  defined  [[scope]] ——>0: demoAO  其中num=100
                                   1: GO

4.m_demo[j]()执行,生成自己的AO{}——> 执行打印i ——> 顶层依次向下寻找 ——> demoAO中的i ——> 打印值
m_demo[j]()  doing  [[scope]] ——>  0:m_demoAO
                                   1: demoAO  i=10
                                   2: GO

如果想打印出从0 到9 ,就用到立即执行函数了,解决方法

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

for (var j = 0; j < 10; j++){
	m_demo[j]();
}

/*

1.初始:
demo() defined  [[scope]] ——>0: GO { m_demo:undefined,demo:function(){...} }

2.var m_demo = demo()执行时:
demo() doing  [[scope]] ——>0: demoAO {arr:[function(){...},function(){...}...] ,i=10 }
                           1: GO
立即执行函数 doing 立即Ao { j:0} {j:1}....
10个function()  defined  [[scope]] ——>0: 立即Ao 
                                      1: demoAO 
                                      2: GO
return arr将 arr[...]返回赋予全局变量m_demo,结果 m_demo=arr[...]

3.var m_demo = demo()执行完毕:
demo() 切断链接demoAO  [[scope]] ——>0: GO  
     但demoAO依旧存在, m_demo[j].[[scope]][1]指向demoAO

m_demo[j]()  defined  [[scope]] ——>0: 立即Ao 
                                   1: demoAO 
                                   2: GO

4.m_demo[j]()执行,生成自己的m_demoAO{}——> 执行打印j ——> 顶层依次向下寻找 ——> demoAO中的i ——> 打印值
m_demo[j]()  doing  [[scope]] ——>  0:m_demoAO {} 
                                   1: 立即Ao  {j=1} {j=1}
                                   2: demoAO 
                                   3: GO
*/

知道闭包如何解决,现在看一下闭包的优势应用吧

1、使用闭包进行模块化开发,防止污染全局变量

var name = 'hh';
var initLi = (function(){
    var name = 'Li';
    function sayName () {
       console.log(name);
    }
	return function () {
		sayName();
	}
}())
initLi();

//结果为Li

var initZhao = (function(){
    var name = 'zhao';
    function sayName () {
       console.log(name);
    }
	return function () {
		sayName();
	}
}())
initZhao();

//结果为zhao

如有错误,欢迎指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值