欢迎在下方发表您的优质见解
函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。
可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。
函数执行分成两个阶段(预编译阶段和执行阶段)。
利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。
应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
var Yideng = (function () {
// 这样声明为模块私有变量,外界无法直接访问
var foo = 0;
function Yideng() {}
Yideng.prototype.bar = function bar() {
return foo;
};
return Yideng;
}());
应用场景二: 在循环中创建闭包,防止取到意外的值。
如下代码,无论哪个元素触发事件,都会弹出 3。因为函数执行后引用的 i 是同一个,而 i 在循环结束后就是 3
for (var i = 0; i < 3; i++) {
document.getElementById('id' + i).onfocus = function() {
alert(i);
};
}
//可用闭包解决
function makeCallback(num) {
return function() {
alert(num);
};
}
for (var i = 0; i < 3; i++) {
document.getElementById('id' + i).onfocus = makeCallback(i);
}
厉害
写的不错
function foo () {
var a = 1
function bar () {
a++;
console.log(a)
}
}
var b = foo()
b()
function foo () {
var a = 1;
function bar () {
a++;
console.log(a)
}
return bar
}
var b = foo()
setInterval(function(){
b()
},1000)
应用场景二说错了,都会弹出 3 是因为 var 的变量提升导致 i 提升成了函数作用域的变量而不是 for 作用域内的变量。解决方法不是创建闭包而是将 var 改成 let 防止循环变量提升成函数变量。
应用场景二说错了,都会弹出 3 是因为 var 的变量提升导致 i 提升成了函数作用域的变量而不是 for 作用域内的变量。解决方法不是创建闭包而是将 var 改成 let 防止循环变量提升成函数变量。
@Genzhen 感谢提出见解
闭包可以缓存值,不被回收,也是这种场景的一种解决方案,在没有let之前,也是经常采用的
写的可以
在vue中有个经常使用的场景,在事件回调中传入额外的值,比如for循环的index。
Most helpful comment
1)什么是闭包
函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。
可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。
2)闭包原理
函数执行分成两个阶段(预编译阶段和执行阶段)。
利用了函数作用域链的特性,一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然在引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被烧毁后才被销毁。
3)优点
4)缺点
4)应用场景
应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
应用场景二: 在循环中创建闭包,防止取到意外的值。
如下代码,无论哪个元素触发事件,都会弹出 3。因为函数执行后引用的 i 是同一个,而 i 在循环结束后就是 3