你对 JavaScript 闭包了解多少?
当我阅读一些文章,希望从中获得灵感,并为接下来的博客文章寻找新的思路时,我的目光落在了 JavaScript 闭包上。我的第一反应是听说过它,可能也了解它。但当我想象着有人来解释它时,我意识到除了它可能在作用域中关闭某些东西之外,我真的不知道它是什么……所以我回到了基础,阅读文章、文档,观看 YouTube 视频,并在其间玩 PS4 来保持理智。这就是我对这个主题的发现。
但为什么你应该关心学习它
比如面试。如果你能解释最令人困惑的话题之一,那将增强你获得工作的优势。
第二个原因,对我来说更个人化,是 React 框架。React Hook API 和函数式组件很大程度上基于闭包。你将更好地理解 Hook 的运作方式。
那么闭包是什么?
在 JavaScript 中,闭包是指可以访问其周围(父级)作用域的函数。每次创建函数时都会创建闭包。借助闭包,函数可以保存状态或拥有本地(私有)变量,即使在父函数被调用并关闭后,这些变量仍然可以被访问。
让我们来看以下示例:
function outer() {
const message = "Hello"; // local variable
function inner() { // a closure function
return message;
}
return inner;
}
const greeting = outer();
greeting() // will return a message "Hello"
这里我们在函数内部有一个message
变量outer
。它是一个局部变量,无法在父函数外部访问。除非我们inner
在父函数内部创建一个闭包函数,否则它可以访问外部作用域和一个变量message
。此外,重要的是返回闭包函数而不调用它。
当我们将函数赋值outer
给变量时greeting
,会发生以下几件事:
outer
函数运行一次并返回一个闭包函数;outer
函数自行关闭greeting
变量变成了函数声明,现在可以访问闭包inner
和message
变量。
现在该greeting
函数已成为函数声明,可以调用它,并且返回的结果将是来自该函数的消息outer
。
考虑到函数被调用一次就自行关闭了,这可能有点奇怪outer
。在某些编程语言中,局部变量仅在函数执行的生命周期内存在。但在 JavaScript 中并非如此。在这里,函数创建闭包,其中包含所有周围环境,例如创建时处于作用域内的变量。
该greeting
函数拥有对闭包函数的引用inner
。后者在outer
函数执行期间创建,并保存了变量所在的环境message
。
在哪里可以使用
你可能已经用过它了,只是你不知道,尤其是在使用过 React 框架的情况下。所有函数式组件的事件处理程序都是闭包。
此外,闭包还可以用于模拟函数的私有方法,类似于类方法。例如:
function setCounter() {
let _counter = 0;
function changeCounter(value) {
_counter += value;
}
return {
increment: () => changeCounter(1),
decrement:() => changeCounter(-1),
getValue: () => _counter,
};
}
const counter = setCounter();
counter.getValue() // returns 0
counter.increment()
counter.getValue() // returns 1
在反例中,我们使用闭包increment
、decrement
和getValue
作为公共函数方法。它们可以访问_counter
函数的值。除了这些方法之外,没有其他方法可以访问_counter
。
让我们构建另一个有状态函数:
function useState(initialValue) {
let _val = initialValue;
const state = () => _val;
const setState = (newValue) => {
_val = newValue
};
return [state, setState];
}
const [count, setCount] = useState(0);
console.log(count()) // returns 0
setCount(5);
console.log(count()) // returns 5
在后一个例子中,我们有两个闭包函数:state
一个返回_val
变量的当前状态,另一个通过修改变量的值来setState
修改_val
变量。这是 React useState
hooks 的一个非常原始的实现。
总结
闭包是一个既难又有趣的话题。当我决定学习并撰写关于它的文章时,我并没有意识到它是如此广泛和令人困惑。本文中的示例非常原始且简短,但我希望你能更好地理解它,尤其是函数如何保存状态。
文章来源:https://dev.to/spukas/what-do-you-know-about-javasscript-closures-4725