闭包指的是那些引用了另一个函数作用域中变量的函数,通常是嵌套函数中实现的。
闭包分析
未使用闭包的作用域链的创建和使用细节的分析:
- 在调用一个函数时,会为这个函数调用创建一个执行上下文,并创建一个作用域链。
用arguments和其他命名对象来初始化这个函数的活动对象。
外部函数的活动对象是内部函数作用域链上的第二个对象。
这个作用域链一直向外串起所有包含函数的活动对象,直至全局执行上下文终止。 - 全局上下文中的叫变量对象,在代码执行期间始终存在
函数局部上下文中的叫活动对象,只在函数执行期间存在
function compare(value1,value2) {
if(value11 < value2) {
return -1;
}else if(value1 > value2) {
return 1;
}else {
return 0;
}
}
let result = compare(5,10);
此处定义的compare()函数是在全局上下文中调用的。
第一次调用compare()时,为它创建一个活动对象,包含(arguments,value1,value2)
此对象是compare()作用域链的第一个对象。
compare()作用域链的第二个对象是全局上下文的变量对象,包含(this,result,compare)
使用闭包的作用域链的创建与细节分析:
function createComparison(propertyName) {
return function(object1,object2) {
//引用了外部函数的变量
let value1 = object1[propertyName];
let value2 = object2[propertyName];
if(value11 < value2) {
return -1;
}else if(value1 > value2) {
return 1;
}else {
return 0;
}
}
}
匿名函数里面引用了外部函数的变量。
在这个内部函数被返回并在其他地方被使用后,仍然引用着那个变量。
在一个函数内部定义的函数会把其包含函数的活动对象添加到自己的作用域链中。
匿名函数的作用域链中实际包含了createComparison()的活动对象
createComparison()的活动对象并不能在执行完成后被销毁,因为匿名函数对它有引用作用。
在createComparison()执行完毕后,其执行上下文的作用域链会销毁,
但活动对象仍然保留在内存中,直到匿名函数被销毁后才会被销毁。
闭包
- 有权访问另一个函数作用域内变量(局部变量)的函数。
- 既可以长久的保存变量又不会造成全局污染
- 返回的是一个函数,并且这个函数对于局部变量存在引用,这就形成闭包
用途:
- 可以在函数外部读取函数内部的变量
- 可以让变量的值始终保持在内存中
- 可以维持多个人的状态
闭包函数的实现
- 闭包的常见创建方式就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量可以在函数外部读取函数内部的变量。
function fn() {
var times = 0;
var c = function () { return ++times; };
return c;
}
var count = fn();
console.log(count()); // 输出结果:1
console.log(count()); // 输出结果:2
console.log(count()); // 输出结果:3
//维持多个人的状态
function f1(){
var a = 10;
return function(){
a++;
console.log(a);
}
};
var a1 = f1()
var a2 = f2()
a1()
a1()
a2()
function xxx(){
var lives = 30
function die(){
lives -= 1
return lives
}
return die
}
var dieFn = xxx()
var currentLives = dieFn()
闭包的作用
闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。
因为如果是全局变量,容易被改,如果是局部变量,别人又访问不到。
上面这样用闭包,就可以用dieFn()来修改lives。
闭包的缺点
由于闭包会使函数中的变量都保存到内存中,垃圾回收机制不清理,内存消耗很大,所以不能滥用闭包,否则可能导致内存泄漏。
什么是内存泄漏???
程序的运行都是需要内存的。只要对内存提出要求,操作系统必须供给内存。
当应用程序中的一些代码变量不再需要用到内存时,但是没有被操作系统或者可用内存池回收,就说明它发生了内存泄漏。
即,当已经不再需要某块内存时,这块内存还存在着——内存泄漏
内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。
闭包里面的变量明明就是我们需要的变量(lives),所以不是内存泄露
为何有人说是?
因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。
解决闭包引起的内存泄露:
在退出函数之前,将不使用的局部变量全部删除。
例如:将当前变量的值设置为‘null’,当垃圾回收机制启动时,会自动对这些值为‘null’的变量回收。