A说:闭包就是函数里面嵌套函数,然后return函数
B说: 可以访问其他函数作用域内变量的函数叫做闭包
C说:函数和函数内部能访问到的变量的总和就叫闭包
查一查JavaScript高级红宝书咋说的吧:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的, 在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
只是为了设计出局部变量和方法,也可以说是私有变量和方法,避免污染全局变量
如果不return,外部就无法使用这个闭包,把return fn改成window.fn = fn也是一样的,所以闭包和return无关
简单来说,让你间接访问一个变量,或者说是隐藏一个变量,再者就是让这个变量保存在内存中
为什么呢?解答来源参考链接1的故事:
“
假设我们在做一个游戏,在写其中关于「还剩几条命」的代码。如果不用闭包,你可以直接用一个全局变量:
window.lives = 30 // 还有三十条命
这样看起来很不妥。万一不小心把这个值改成 -1 了怎么办。所以我们不能让别人「直接访问」这个变量。怎么办呢? ----- 用局部变量
但是用局部变量别人又访问不到,怎么办呢? ----- 暴露一个访问器(函数),让别人可以「间接访问」
代码如下:
!function(){
var lives = 50
window.奖励一条命 = function(){
lives += 1
}
window.死一条命 = function(){
lives -= 1
}
}()
”
故事讲完了,回到第一句话,作用就是让你间接访问一个变量,或者说是隐藏一个变量
闭包允许将函数和其所操作的某些数据关联起来
function makeSizer(size){
return function(){
docment.body.style.fontSize = size + 'px'
}
}
var size12 = makeSizer(12)
size12()
模拟私有方法
var Counter = (function(){
var privateCounter = 0
function changeBy(val){
privateCounter += val
}
return {
increment:function(){
changeBy(1)
},
decrement:function(){
changeBy(-1)
},
value:function(){
return privateCounter
}
}
})()
解决循环中闭包的创建方法
比如DOM事件回调、定时器回调等
//定时器方法一
for(var i = 0; i <= 5; i++){
(function(i){
setTimeout(function(){
console.log(i)
},1000)
})(i)
}
//定时器方法二
for(var i = 0; i <= 5; i++){
setTimeout(function(i){
return function(){
console.log(i)
}
}(i),1000)
}
1、使用闭包存在内存泄漏,是因为IE,IE在在我们使用完闭包之后,仍然回收不了闭包里面引用的变量,解决办法就是使用完闭包之后手动将变量删除。
2、 因为闭包会保留它们包含函数的作用域,所以比其他函数更占用内存。过度使用闭 包可能导致内存过度占用,因此建议仅在十分必要时使用。V8等优化的 JavaScript引擎会 努力回收被闭包困住的内存,不过我们还是建议在使用闭包时要谨慎。
在闭包中使用this会让代码变复杂,如果内部函数没有使用箭头函数定义,则this对象会在运行时绑定到执行函数的上下文。如果在全局函数中调用,在非严格模式下this等于window,严格模式下this等于undefined。如果作为某个对象的方法调用,则this指向这个对象。匿名函数在这种情况下不会绑定到某个对象,这意味着this指向window。看下面的例子:
window.identity = 'The Window'
let object = {
identity: 'My Object',
getIdentityFunc() {
return function() {
return this.identity
}
}
}
console.log(object.getIdentityFunc()()); // 'The Window'
解析:
将最后一步拆分成两步走:
var first = object.getIdentityFunc() //返回一个匿名对象
var second = first() //函数调用
第一步中:getIdentityFunc()
是作为object对象的方法调用的,如果在getIdentityFunc()
中使用this,那么this指向的是object对象,这毫无疑问。
第二步:调用first函数,可知并没有在object对象中调用,因此是作为函数在全局作用域下调用的,first函数中this指向window,这也是可以理解的。
为什么匿名函数没有使用其包含作用域(getIdentityFunc()
)的this对象呢?
每个函数在被调用时都会自动创建两个特殊变量:this
和arguments
。内部函数永远不可能直接访问外部函数的这两个变量,但是,将this保存到闭包可以访问的一个变量中,则是行得通的。比如:
window.identity = 'The Window'
let object = {
identity: 'My Object',
getIdentityFunc() {
let that = this
return function() {
return that.identity
}
}
}
console.log(object.getIdentityFunc()()); // 'My Object'
getIdentityFunc()
中的that指向object,所以调用object.getIdentityFunc()()
会返回“My Object”
https://zhuanlan.zhihu.com/p/22486908
https://github.com/GZ0759/StudyNotes/blob/master/INTERVIEW/JavaScript%E5%AE%9E%E8%B7%B5%E7%AF%87.md
https://www.cnblogs.com/nuanriqingfeng/p/5789003.html
JavaScript高级程序设计(第4版)