目录
  1. 1. 闭包
    1. 1.1. 如何产生闭包?
    2. 1.2. 闭包到底是什么?
    3. 1.3. 产生闭包的条件?
    4. 1.4. 常见的闭包
    5. 1.5. 闭包的作用
    6. 1.6. 闭包的生命周期
      1. 1.6.1. 产生
      2. 1.6.2. 死亡
    7. 1.7. 闭包的应用
    8. 1.8. 自定义JS模块
      1. 1.8.1. 模块1
      2. 1.8.2. 模块2
    9. 1.9. 闭包的缺点与解决方法
    10. 1.10. 闭包面试题
      1. 1.10.1. 题一
JS初识闭包

闭包

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

接下来看三段代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>00_引入</title>
</head>
<body>

<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
<!--
需求: 点击某个按钮, 提示"点击的是第n个按钮"
-->
<script type="text/javascript">
var btns = document.getElementsByTagName('button')
//遍历加监听

/*1.
for (var i = 0,length=btns.length; i < length; i++) {
var btn = btns[i]
btn.onclick = function () {
alert('第'+(i+1)+'个')
}
}*/


/*2.
for (var i = 0,length=btns.length; i < length; i++) {
var btn = btns[i]
//将btn所对应的下标保存在btn上
btn.index = i
btn.onclick = function () {
alert('第'+(this.index+1)+'个')
}
}*/

//3. 利用闭包
// for (var i = 0,length=btns.length; i < length; i++) {
// (function (j) {
// var btn = btns[j]
// btn.onclick = function () {
// alert('第'+(j+1)+'个')
// }
// })(i)
// }

</script>
</body>

</html>

第一段代码是无法实现我们想要实现的结果的,而后两者可以实现

如何产生闭包?

当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包

执行函数定义就会产生闭包(不用调用内部函数)

闭包到底是什么?

  • 使用chrome调试查看
 function fn1 () {
var a = 2
var b = 'abc'
fn2()
function fn2 () { //执行函数定义就会产生闭包(不用调用内部函数)
console.log(a)
}

}
fn1()

  • 理解一: 闭包是嵌套的内部函数(绝大部分人)
  • 理解二: 包含被引用变量(函数)的对象(极少数人)
  • 注意: 闭包存在于嵌套的内部函数中

产生闭包的条件?

  • 函数嵌套
  • 内部函数引用了外部函数的数据(变量/函数)

常见的闭包

  1. 将函数作为另一个函数的返回值
function fn1() {
var a = 2
function fn2() {
a++
console.log(a)
}
return fn2
}

var f = fn1()
f() // 3
f() // 4

为了方便理解,此处返回的fn2则为图中标注这块儿

  1. 将函数作为实参传递给另一个函数调用
function showDelay(msg, time) {
setTimeout(function () {
alert(msg)
}, time)
}
showDelay('闭包', 2000)

闭包的作用

作用:

  • 延长局部变量的生命周期——缓存数据
    • 如果想要缓存数据,就把这个数据放在外层的函数和里层的函数的中间位置
    • 局部变量是在函数中,函数使用结束后,局部变量就会被自动的释放
    • 闭包后,里面的局部变量的使用作用域链就会被延长
  • 让函数外部能操作内部的局部变量

闭包的生命周期

产生

在嵌套内部函数定义执行完时就产生了(不是在调用)

死亡

在嵌套的内部函数成为垃圾对象时

function fn1() {
//此时闭包就已经产生了(函数提升, 内部函数对象已经创建了)
var a = 2
function fn2 () {
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() // 3
f() // 4
f = null //闭包死亡(包含闭包的函数对象成为垃圾对象)

闭包的应用

  • 具有特定功能的js文件
  • 将所有的数据和功能都封装在一个函数内部(私有的)
  • 只向外暴露一个包信n个方法的对象或函数
  • 模块的使用者, 只需要通过模块暴露的对象调用方法来实现对应的功能

自定义JS模块

模块1

myModule.js

function myModule() {
//私有数据
var msg = '闭包'
//操作数据的函数
function doEat() {
console.log('doEat() '+msg.toUpperCase())
}
function doDance () {
console.log('doDance() '+msg.toLowerCase())
}

//向外暴露对象(给外部使用的方法)
return {
doEat: doEat,
doDance: doDance
}
}

file1

<script type="text/javascript" src="myModule.js"></script>
<script type="text/javascript">
var module = myModule()
module.doEat()
module.doDance()
</script>

模块2

myModule2.js

(function () { // 匿名函数自调用
//私有数据
var msg = 'My atguigu'
//操作数据的函数
function doSomething() {
console.log('doSomething() '+msg.toUpperCase())
}
function doOtherthing () {
console.log('doOtherthing() '+msg.toLowerCase())
}

//向外暴露对象(给外部使用的方法)
window.myModule2 = {
doSomething: doSomething,
doOtherthing: doOtherthing
}
})()

file2

<script type="text/javascript" src="myModule2.js"></script>
<script type="text/javascript">
myModule2.doSomething()
myModule2.doOtherthing()
</script>

可以发现模块2的好处是不用定义方法,可直接采取调用,使用更加简单方便

闭包的缺点与解决方法

  • 缺点
    • 函数执行完后, 函数内的局部变量没有释放, 占用内存时间会变长
    • 容易造成内存泄露
  • 解决
    • 能不用闭包就不用
    • 及时释放
function fn1() {
var arr = new Array(100000)
function fn2() {
console.log(arr.length)
}
return fn2
}
var f = fn1()
f()
f = null //让内部函数成为垃圾对象-->回收闭包

闭包面试题

题一

//代码片段一
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
console.log(object.getNameFunc()()); // the window


//代码片段二
var name2 = "The Window";
var object2 = {
name2 : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name2;
};
}
};
console.log(object2.getNameFunc()()); // my object
文章作者: Jachie Xie
文章链接: https://xjc5772.github.io/2020-03/23/%E5%AD%A6%E4%B9%A0/%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0/JS/JS%E5%88%9D%E8%AF%86%E9%97%AD%E5%8C%85/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 XJC&Blog
打赏
  • 微信
  • 支付宝

评论