昨日在看JavaScript语言安全编码规范中有这么一条
问题来了,看不很懂。所以来捋一捋。
首先理清楚几个基本概念:
变量作用域
变量可分为全局变量和局部变量。全局变量的作用域就是全局性的,在 js 的任何地方都可以使用全局变量。在函数中使用 var 关键字声明变量,这时的变量即是局部变量,它的作用域只在声明该变量的函数内,在函数外面是访问不到该变量的。
var func = function(){
var a = 'test';
console.log(a); // test
}
func();
console.log(a); // Uncaught ReferenceError: a is not defined
变量生存周期
全局变量,生命周期是永久的。局部变量,当定义该变量的函数调用结束时,该变量就会被垃圾回收机制回收而销毁。再次调用该函数时又会重新定义了一个新变量。
正如上面那个例子,a为局部变量,func调用完之后,a就被销毁了。
看下面这个例子
var func = function(){
var a = test;
var func1 = function(){
a += ' a';
console.log(a);
}
return func1;
}
var func2 = func();
func2(); // test a
func2(); // test a a
func2(); // test a a a
可以看出,在第一次调用完 func2 之后,func 中的变量 a 变成 'test a',而没有被销毁。因为此时 func1 形成了一个闭包,导致了 a 的生命周期延续了。
所以什么是闭包,闭包就是能够读取其他函数内部变量的函数。如上面这个例子,func1就是一个闭包,闭包使用了其他函数定义的变量使其不能销毁。
再来看一下存在闭包情况下的内存管理
在闭包中调用局部变量,会导致这个局部变量无法及时被销毁,相当于全局变量一样会一直占用着内存。如果需要回收这些变量占用的内存,可以手动将变量设置为null。
然而在使用闭包的过程中,比较容易形成 JavaScript 对象和 DOM 对象的循环引用,就有可能造成内存泄露。这是因为浏览器的垃圾回收机制中,如果两个对象之间形成了循环引用,那么它们都无法被回收。
function func() {
var test = document.getElementById('test');
test.onclick = function () {
console.log('hello world');
}
}
在上面例子中,func 函数中用匿名函数创建了一个闭包。变量 test 是 JavaScript 对象,引用了 id 为 test 的DOM 对象,DOM 对象的 onclick 属性又引用了闭包,而闭包又可以调用 test ,因而形成了循环引用,导致两个对象都无法被回收。要解决这个问题,只需要把循环引用中的变量设为 null 即可。
function func() {
var test = document.getElementById('test');
test.onclick = function () {
console.log('hello world');
}
test = null;
}
如果在 func 函数中不使用匿名函数创建闭包,而是通过引用一个外部函数,也不会出现循环引用的问题。
function func() {
var test = document.getElementById('test');
test.onclick = funcTest;
}
function funcTest(){
console.log('hello world');
}
那么现在回过头来理解安全编码规范中的那个问题
因此,互相持有,类似死锁一样,都不能释放掉,导致这部分内存不能释放,解决方式就是打开环,如方法二中所说的。 调用外部函数则断开了函数对element对象的引用。从而避免内存泄露。
使用闭包要注意如下问题
1.内存消耗
通常来说,函数的活动对象会随着执行期上下文一起销毁,但是,由于闭包引用另外一个函数的活动对象,因此这个活动对象无法被销毁,这意味着,闭包比一般的函数需要更多的内存消耗。尤其在IE浏览器中需要关注。由于IE使用非原生javascript对象实现DOM对象,因此闭包会导致内存泄露问题
2.性能问题
使用闭包时,会涉及到跨作用域访问,每次访问都会导致性能损失。
因此在脚本中,最好小心使用闭包,它同时会涉及到内存和速度问题。不过我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响。
By HW WL





































苏公安网备 32011402010933号