JavaScript 的闭包是指一个函数可以访问并操作其外部作用域中的变量,即使在该函数执行结束后也是如此。JavaScript 的闭包是一种非常有用的特性,可以被应用于很多场景。
闭包的核心概念是函数内部的作用域链。每当一个函数被创建时,它都会自动创建一个与之相关的作用域链。该作用域链具备以下两个特点:
里面包含了所有父级作用域的变量,这些变量可以被当前函数内部访问和使用
外部函数无法访问当前函数内部的变量,除非该内部变量被显式地返回或者暴露出去。
以下是一个简单的闭包示例,在这个示例中,函数 outer() 内部定义的变量 innerVar 和函数 inner() 都是闭包。
function outer() {
var innerVar = "I'm in a closure!";
function inner() {
console.log(innerVar);
}
return inner;
}
var closure = outer();
closure(); // => 输出 "I'm in a closure!"
从上面的代码片段中可以看到,我们调用 outer() 函数并将其结果存储为变量 closure。该变量实际上是 inner() 函数的引用。当我们调用 closure() 时,innerVar 变量的值被打印到控制台中。这是因为闭包可以访问其父级作用域中的变量和函数,而不受其生命周期的限制。
闭包的应用场景非常多,以下是一些常见的使用方式:
通过使用闭包来创建私有属性和方法,我们可以将一些变量和函数“封装”在当前对象的作用域内,从而防止它们被其他代码访问和污染。例如,下面的示例中,我们使用闭包创建了一个保存计数器的对象,并且该计数器对外部代码是不可见的。
var Counter = (function() {
var count = 0;
return {
increment: function() {
count++;
},
decrement: function() {
count--;
},
getCount: function() {
return count;
}
}
})();
Counter.increment();
console.log(Counter.getCount()); // => 输出 1
通过使用闭包来实现模块化的开发方式,我们可以将一些相关函数和变量组织起来,从而更好的协同工作。例如,假设我们有一些操作 DOM 元素的函数,我们可以将这些函数打包成一个闭包并返回,从而避免全局命名冲突和代码重复。像下面这个例子所示,我们可以创建一个 IIFE(立即调用的函数表达式) 来实现该功能:
var MyDOM = (function() {
function getElement(selector) {
return document.querySelector(selector);
}
function setText(selector, text) {
getElement(selector).textContent = text;
}
return {
setText: setText
}
})();
MyDOM.setText('#message', 'Hello World!');
函数式编程(Functional Programming)是一种基于函数的软件开发范式。JavaScript 的闭包可以帮助我们更好地实现函数式编程,并且可以使代码更加简单和易于理解。
例如,下面的示例中,我们使用闭包来实现一个柯里化的 add() 函数:
function add(x) {
return function(y) {
return x + y;
}
}
var add2 = add(2);
console.log(add2(3)); // => 输出 5
以上就是 JavaScript 闭包的概念及其常见应用场景。