谈谈js闭包
在平时的js开发中,有时候你可能不知不觉就在使用js闭包,js闭包到底是啥呢?今天就来聊一聊,闭包是js高级特性, 闭包是指:可以访问另一个函数作用域的变量的函数。也就是说闭包有两个特点,1.闭包是一个函数。2.这个函数可以访问其他函数的作用域中的变量。
举个例子:
function funA() {
var a = '变量1';
var funB = function() {
console.info(a);
}
return funB // funB 就是一个闭包函数,因为他能够访问到funA函数的作用域
}
闭包是站在作用域的角度上来定义的,因为funB访问到funA作用域的变量,所以funB就是一个闭包函数。
js的变量作用域分为全局和局部,根据作用域链相关知识,js访问变量是由内向外的,内部作用域可以获得当前作用域下的变量和包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问各自的变量的,如果我们想在一个函数内部获取另一个函数内部的变量该怎么办呢?对你肯定也想到了。可以使用闭包,其实闭包的本质就是在一个函数内部创建另一个函数。
eg:
function getStr() {
var str = 'abcd';
return function() {
return str
}
}
var demoA = getStr();
console.log(demoA()); //abcd
上面代码中,getStr()中的返回一个匿名函数,这个函数在getStr()作用域内部,所以它可以获取getStr()作用域下变量str的值,将这个值作为返回值赋给全局作用域下的变量demoA ,实现了在全局变量下获取到局部变量中的变量的值。
在看个例子:
for (var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000)
}
控制台打印的结果:
按照预期应该依次输出0 2 3…9,而结果它输出了10次10,这是因为在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值已经变成了10,所以打印出来10个10。如果想实现预期结果可以这样做。
for (var i = 0; i < 10; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000)
})(i)
}
控制台打印结果:
也可以使用es6语法把for循环里面的var变成let,也能实现同样的效果。
闭包的优缺点:
优点:
变量可以长时间存储在内存中
避免污染全局变量
缺点:
消耗内存
容易造成内存泄露