定义
闭包是一个函数及其词法环境的组合。这个词法环境包含了闭包被创建时的所有局部变量以及其他闭包。 简言之,闭包允许一个函数访问并操作函数外部的变量。在 JavaScript 中,每当一个函数被创建,闭包就会自动形成,连接内部函数与其外部作用域的变量。 例如
functio init() {
const name = "M"; //name 是由 init 创建的局部变量。
function displayName(){ //displayName() 是一个内部函数,是一个闭包。
alert(name); //使用了父函数 init() 中声明的变量。
}
displayName();
}
init();
以上例子中,displayName()函数是一个闭包,因为它能够访问并使用其外部函数 init() 的局部变量 name。
使用场景及优势
- 创建私有变量:JavaScript的函数作用域使得闭包成为实现私有变量和私有方法的强大工具,因为这些变量对于外部代码不能直接访问。
var counter = (function() {
var privaterCounter = 0;
function changeBy(val) {
privaterCounter += val;
}
return {
increment(){
changeBy(1);
},
decrement(){
changeBy(-1);
},
value:function(){
return privaterCounter;
}
}
})();
- 延长变量的生命周期:通常,函数内的局部变量在函数执行完会被销毁。闭包可以延长这些变量的生命周期,使其在函数执行完后仍能访问。
- 柯里化(currying):闭包允许轻松地重用和应用函数,对于需要频繁调用相同参数的函数非常有用。例如,一个接受两个参数的函数
f(a, b)通过柯里化后,会变成f(a)(b)的形式。
function add(a) {
return function(b) {
return a + b;
};
}
const addFive = add(5);
console.log(addFive(2)); // 输出 7
- 模拟私有方法:使用闭包可以模拟私有方法的功能,使某些函数和变量对外部代码不可见,增加了代码的封装性和安全性。
注意事项:
- 性能考虑:闭包可能会导致比较高的内存使用,因为闭包中的变量不会在外部函数执行完后立即被销毁。不恰当的使用闭包可能会导致内存泄漏。
- 方法定义:在创建对象或类时,应避免在构造器中定义方法。相反,这些方法应定义在对象的原型上,这样可避免每次实例化对象时都重新定义这些方法。