📅  最后修改于: 2023-12-03 15:28:49.355000             🧑  作者: Mango
在Javascript中,闭包是一种非常重要的概念。其实闭包并不难理解,而且学习好闭包可以让你更好地理解 Javascript 的本质。
闭包就是一个可以访问外部函数作用域中变量的函数。简言之,就是一个函数能够把外部作用域中的变量捆绑到该函数内部,使得这些变量在该函数的生命周期内一直存在。
说起来有点抽象,我们来看一个例子:
function outer() {
let num = 0;
function inner() {
num++;
console.log(num);
}
return inner;
}
let fn1 = outer();
let fn2 = outer();
fn1(); // 1
fn1(); // 2
fn2(); // 1
在这个例子中,outer
函数返回了一个函数 inner
。inner
函数中调用了外部作用域中的变量 num
。由于 inner
作为闭包,它会一直保存对其父作用域的引用,所以每次调用 fn1()
时,都能够正确地获取到 outer
中定义的 num
变量,并维持 num
的值的连续性。
如果我们没有学习闭包时,可能会使用全局变量或者函数传递参数来实现某些需求,但是这些做法固然没有问题,但却会让代码不够优雅,而且无法避免变量名污染的问题。
闭包则是解决这些问题的利器。我们可以使用闭包来隐藏实现细节,同时又能够保证变量的私有性。比如在一个定时器回调函数中访问jQuery的对象,使用闭包可以避免全局变量的定义:
function start() {
let num = 0;
setInterval(function() {
num++;
console.log(num);
$("#myDiv").html(num);
}, 1000);
}
start();
在这个例子中,我们使用了闭包来隐藏了变量 num
,同时又在定时器回调函数中访问到它。
闭包对性能的影响是不容忽视的,因为函数的变量会被保存在内存中。在一些情况下,如果没有正确地使用闭包,可能会导致内存泄漏的问题。比如下面这个例子:
function createArray() {
let arr = [];
for (let i = 0; i < 100000; i++) {
arr.push(function() {
console.log(i);
});
}
return arr;
}
let arr = createArray();
arr[0](); // 100000
在这个例子中,我们使用了循环来创建包含函数的数组。但是由于闭包的引用机制,实际上每个函数都会引用最后一个 i
的值,因此当我们调用 arr[0]()
时,输出的结果是 100000
而非我们期望的 0
。这种情况下,我们可以使用立即执行函数来避免这个问题:
function createArray() {
let arr = [];
for (let i = 0; i < 100000; i++) {
(function(k){
arr.push(function() {
console.log(k);
});
})(i);
}
return arr;
}
let arr = createArray();
arr[0](); // 0
这种情况下,我们将循环内的函数改为了立即执行函数,并将 i
作为参数传入,从而避免了闭包引用的问题。
闭包作为 Javascript 的一个重要概念,无论是从实践还是理论上,都应该好好掌握。在实际的开发中,我们可以用闭包来保证变量的私有性、隐藏实现细节,同时又规避了全局变量带来的模块污染等问题。但是在使用闭包时需要注意,一定要正确地引用外部变量,避免可能存在的内存泄漏等问题。