浅谈js闭包
闭包的意义
在谈论闭包是什么之前,我们要先明白为什么我们要使用闭包,它能带给我们什么,又会有哪些弊端。在最开始,大家了解到的很多关于闭包的标签可能会有包括内存泄漏,内部函数读取外部数据等等。但是为什么大家还要去用闭包呢?我认为闭包有以下几点意义:
闭包存在的原因以及实现
说到闭包就不得不提一下js的垃圾回收机制,正是这种机制的存在,使得闭包能够使用。
引用计数:如果一个对象的引用计数为0,也就是说,没有一个指针能够指向它,则对象就会被回收内存。而js函数里的变量都是临时的,当函数执行结束后就会清除。再次进入函数内就会造成变量初始化,例如:
function add() {
var counter = 0;
return counter += 1;
}
add() //1
add() //1
add() //1
原本我们预期每次执行add函数时,都会让内部的couter++,也就是希望输出1,2,3。但是现在由于变量的重复初始化和函数执行完毕后的变量清空,我们只能每次都输出1。
接着,我们尝试在函数内部再使用一个函数来对couter进行++,返回couter,但是返回的结果仍然会一直为1。
function add() {
var counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
add() //1
add() //1
add() //1
细心的小伙伴结合上面我们提到的知识可能已经想到了:虽然我们在add函数内部加入了plus函数再返回couter,但是在add结束后,couter和plus函数的引用都消失了,所以这时候它们已经被回收掉了。再次执行函数add也只能是再次初始化进行一样的事情。
这时候聪明的小伙伴可能又想到了,如果我们能把里面的plus函数在外面引用,再在plus函数里留下对add函数内变量的引用,不就可以让他们一直保存在内存中了吗?说干就干,我们来试试:
function newAdd() {
let num = 0
function fn() {
return num++
}
return fn
}
let add=newAdd()
add() //1
add() //2
add() //3
我们发现现在可以跑通了,让我们来分析一下实现的原理。我们返回了一个函数,在函数内部返回了couter++。当我们在执行add()的时候,其实就是执行了newAdd函数返回的函数fn,在fn中,我们需要去寻找couter,根据js作用域链逐层往上寻找的原理,fn会往newAdd函数内去寻找,找到了num。这个时候,这整个链条就被保存下来了,让它的引用计数不会为0,一直保存在内存中。我们也知道一点,在js中,函数如果不加括号,表示的是指针,指向保存它的内存。如果我们已经确定这一部分变量、函数已经不再被需要了,就要设置js add=null
来解除引用。这时候js引擎检测到有一部分内存已经不可达了,就会去释放这部分内存。
如果有小伙伴还想进一步了解闭包,可以去看看执行上下文和作用域链的相关知识,相信你会了解更加深刻。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!