目录
一、前提知识:变量的作用域
二、闭包的理解
三、闭包的作用
四、常见的闭包使用形式
五、闭包的生命周期
六、注意事项
一、前提知识:变量的作用域
变量的作用域分为全局作用域和局部作用域,也就是全局变量和局部变量。JavaScript有一个特殊的地方是函数内部可以直接读取全局变量,但是在函数外部,无法读取到函数内部的变量。
//函数内部直接读取全局变量
var a = 100
function fn1(){
console.log(a)
}
fn1() //100
//函数外部无法读取函数内的局部变量
function fn1(){
var a = 100
}
console.log(a) //error
这里注意:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上声明了一个全局变量!
function fn1(){
a = 100
}
console.log(a) //100
那么问题来了:
对函数内部变量进行一系列操作之后,需要在函数外部访问到,怎么才能实现呢?这就需要使用闭包了。
二、闭包的理解
针对上述问题:我们可以在函数内部嵌套一个子函数,将子函数作为外部函数的返回值。如下:
<script>
function fn1(){
var myName = "唯一的阿金"
function fn2(){
console.log("myName = ",myName)
}
return fn2
}
var result = fn1()
result()
</script>
打印结果如下:
在上面的代码中,函数 fn2 被包括在函数 fn1 内部,这时 fn1 内部的所有局部变量,对 fn2 都是可见的。但是,fn2 内部的局部变量,对 fn1是不可见的。这是 Javascript 特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
我们可以利用这一特点,把 fn2 作为返回值,就可以在fn1函数外部访问 fn1 的内部变量了。这个fn2函数,就是闭包。
简单理解,闭包就是能读取函数内部变量的函数。
闭包的产生条件:
当一个嵌套的内部子函数引用了嵌套的外部父函数的变量(这个变量也可以是函数)时,闭包就产生了。
三、闭包的作用
闭包有两大作用:
- 在函数外部读取函数内部的变量
- 让这些变量的值始终保持在内存中,不被销毁
<script>
function fn1(){
var myName = "唯一的阿金"
addName = function(){
myName += ",你好!"
}
function fn2(){
console.log("myName = ",myName)
}
return fn2
}
var result = fn1()
result()
addName()
console.log("*****调用addName()后****")
result()
</script>
打印结果如下:可以看到函数内部的局部变量myName在函数调用后并没有被销毁,在执行addName函数(它是一个全局变量)后,改变了myName变量的值。
四、常见的闭包使用形式
1. 将函数作为另一个函数的返回值使用
这种形式,上述代码已经演示过,这里不再赘述。
2.将函数作为实参传递给另一个函数调用
function showDelay(msg,time){
setTimeout(function(){
console.log(msg)
},time)
}
showDelay("唯一的阿金,你好!",1000)
setTimeout()函数的第一个参数是函数,同时函数内部调用了外部函数showDelay()的局部变量,因此产生了闭包。
闭包的应用主要有:
- 模仿块级作用域,
- 实现柯里化,
- 在构造函数中定义特权方法、
- Vue中数据响应式Observer中使用闭包等。
五、闭包的生命周期
1. 产生:在内部函数定义执行时产生
<script>
function fn1(){
var myName = "唯一的阿金"
function fn2(){
console.log("myName = ",myName)
}
return fn2
}
var result = fn1() //产生闭包
result()
</script>
2. 死亡:在内部函数成为垃圾对象时
<script>
function fn1(){
var myName = "唯一的阿金"
function fn2(){
console.log("myName = ",myName)
}
return fn2
}
var result = fn1() //产生闭包
result = null //闭包死亡
</script>
六、注意事项
1. 闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
- 解决方法:在退出函数之前,将不使用的局部变量全部删除。
2. 由于闭包会在父函数外部,改变父函数内部变量的值。因此,在把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value)时,要小心,不要随便改变父函数内部变量的值。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)