了解闭包之前我们需要懂的东西:需要知道JS的作用域链以及预解析。
进入话题,作用域链上面的东西是存在哪里的呢。 是一个栈结构,最底层是window对象。
栈就是类似一个桶装结构,如图1:
图一 :
栈结构具有的特点就是先入后出。 好比你放进桶里的东西,你需要从最上面开始拿出来。
JS代码的解析过程中:例如JS代码里有一个函数foo.
var a = 1;
function foo()
{ }
foo();
预解析:那么预解析到这个函数时,发生了如下的事情: 由于函数是引用类型的对象,实际数据存在堆里,那么在栈里只存放了地址。0x1101这个地址指向堆的实际数据。
运行到这个函数时,它会创建一个foo的作用域链对象。然后存入一个栈里,这个栈底层永远是window.
函数执行=>foo() 又会发生的事情:栈里面的foo创建了一个活动对象。即执行了这个函数。
当函数执行完毕:foo的作用域链出栈,没有被指向的活动对象即销毁。但是window不会被销毁。
(PS:橡皮擦太小了,没擦干净)
闭包是什么呢? 官方解答是有权去访问函数内的变量。
我们现在来写一个函数:
function foo(){var n = 0;//返回了一个函数。 这个函数的n 是从foo里面找的n。
returnfunction getNum()
{
n++;
console.log(n);returnn;
}
}var fn =foo();
fn();
预解析就会多了一步:在执行foo的时候,也就是创建活动对象之后,会再执行 getNum的入栈步骤。getNum被调用时也会创建一个活动对象。但是最后并不会销毁。
因为fn指向了这个闭环回路。
简单的讲:这个函数被保存在了内存之中,并且一直可以通过fn访问到。
函数调用结束后:如果用fn指向这个getNum的作用域链对象。只要fn到getNum的指向没有消失。那么就可以一直访问到存储在内存的n.
闭包的核心就是getNum的活动对象没有被销毁,即使fn指向不是这个getNum 这个东西封闭的环也不会注销,会一直在内存中,这也是闭包的缺点,容易造成内存泄漏。
我们现在来梳理一下闭包的步骤:
1.函数内部嵌套子函数,
2.子函数得到父函数的值。
3.把内层函数返回出去。(但闭包的创建不止这个形式。还有其他的。)
PS:如何回答的一个技术记汇,或你对xxxx的理解
例如:你说一下对闭包的理解
答:1.xxx是什么
2.应用场景
3.优缺点
4.具体实现
5.还有没有更好的解决方案!