变量的作用域有两种:全局变量和局部变量;函数内部可以直接读取全局变量;在函数外部无法读取函数内的局部变量。
能够读取其他函数内部变量的函数,就是闭包。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
一、定义:闭包是指有权访问另一个函数作用域中变量的函数。创建闭包最常见的方式就是,在一个函数内部创建另一个函数。
由于在JS中,函数内部的变量的作用域属于函数作用域,在函数执行后作用域就会被清理、内存也随之被收回,但是由于闭包是建立在一个函数内部的子函数,由于其可访问上级作用域的原因,即使上级函数执行完,作用域也不会随之销毁,这时的子函数—也就是闭包,便拥有了访问上级作用域中的变量的权限,即使上级函数执行完后,作用域内的值也不会被销毁。
二、常见的一些闭包举例:timer函数就是一个闭包
function foo(a) {
setTimeout(function timer(){
console.log(a)
}, 1000)
}
foo(2);
foo函数
执行1000ms
后,它的内部作用域不会消失,timer
函数依然保有 foo
作用域的引用。timer函数就是一个闭包。
function f1(){
var n=999;
function f2(){
console.log(n);
}
return f2;
}
var result=f1();
result(); // 999
把f2作为f1的返回值,就可以在f1外部读取它的内部变量n。
三、闭包的作用:
由于闭包可以缓存上级作用域,那么就使得函数外部打破了“函数作用域”的束缚,可以访问函数内部的变量。所以在函数外部也可以访问到函数内部的变量。
( 1 ) 一个是在函数外部也可以读取函数内部的变量;
( 2 ) 另一个就是让这些变量的值始终保存在内存中。
四、 闭包的特性
- 函数内部嵌套函数
- 函数外部可以引用函数内部的变量
- 参数和变量不会被垃圾回收机制回收
- 不正确使用闭包可能会导致内存泄漏,如果在闭包中不小心引用了大量的内存资源,这些资源可能不会被及时释放,导致内存泄漏
- 闭包内的数据是无法直接访问的,闭包的特性之一就是可以创建一个封闭的作用域,将闭包内的变量和函数私有化,并通过闭包返回一个函数或引用,使得外部无法直接访问到闭包内的数据,然而,闭包内的数据可以通过闭包返回的函数或引用来间接访问。由于闭包内的数据仍然存在于内存中,闭包所返回的函数或引用持有对这些数据的引用,因此在闭包返回的函数内部,可以访问和操作闭包内的数据。
下面是一个示例,演示了如何通过闭包返回的函数来访问闭包内的数据
-
function createCounter() { let count = 0; function increment() { count++; console.log(count); } return increment; } const counter = createCounter(); counter(); // 输出: 1 counter(); // 输出: 2
五、 闭包的this指向:取决于闭包函数的调用方式
六、闭包的总结:
闭包是指在函数内部创建并返回的函数,可以访问和操作其创建时所处的上级函数的作用域中的变量。
垃圾回收机制:
垃圾回收机制(Garbage Collection)是一种自动管理内存的机制,它负责检测和回收不再使用的内存资源,以便重新分配给其他需要的部分。在JavaScript中,垃圾回收器会定期扫描内存,找到不再被引用的对象,并释放这些对象所占用的内存空间。
内存泄漏:
内存泄漏指的是程序中分配的内存资源在不再需要时无法被正确释放或回收,从而导致内存占用不断增加,最终可能导致程序性能下降或崩溃。