闭包问题
前言:基础知识点
- js的作用域:在js中 函数内部可以读取函数外部变量,相反不可以。
- 作用域销毁:只是切断函数与AO(执行期上下文)的链接,并不是真实销毁AO的存在
总结:
- 闭包是什么:内部函数被保存到外部时,生成闭包
- 闭包缺点:闭包会导致原有作用域链不释放,造成内存泄漏
- 闭包用处:
实现公有变量 ;
实现缓存;
实现封装,属性私有化;
模块化开发,防止污染全局变量
闭包举栗子,如下
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
如有错误,欢迎指正。