一个示例,就能让你了解JS闭包的功能作用是什么
作者:admin 时间:2022-6-3 7:24:58 浏览:在一个函数外面加一个括号,就成为了一个闭包,说实在的,闭包函数在实际编程中用得并不多,但是这却是学习JavaScript必须掌握的知识,并且,闭包是前端考试/面试的必考题。因此,我们要学会和懂得使用这个知识点。在本文中,将通过一个示例,让你了解闭包的功能作用是什么。
示例
场景设计:有个函数体是一个计数器,我现在要让计数器初始值增加3,如何编写代码?
普通函数实现的思路
使用普通函数实现的思路是这样:
var counter = 0;
function add() {
return counter += 1;
}
add();
add();
add();// 计数器现在为 3
输出
现在我们已经达到了目的,可是问题来了,代码中的任何一个函数都可以随意改变counter
的值,因为counter
是一个全局变量,所以这个计数器并不完美。那我们把counter
放在add
函数里面不就好了么?
function add() {
var counter = 0;
return counter += 1;
}
add();
add();
add();// 本意是想输出 3, 但输出的都是 1
输出
所以这样做的话,每次调用add
函数,counter
的值都要被初始化为0,还是达不到我们的目的。
使用闭包的实现思路
这时候我们可以用闭包去解决这个问题了,先看代码。
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
add();
add();
add();// 计数器为 3
这时候我们完美实现了计数器。这段非常精简,可以拆分成如下等价代码。
function outerFunction () {
var counter = 0;
function innerFunction (){
return counter += 1;
}
return innerFunction;
}
var add = outerFunction();
add();
add();
add();// 计数器为 3
输出
这时候的add
就形成了一个闭包。一个闭包由两部分组成,函数和创建该函数的环境。环境是由环境中的局部变量组成的。对于闭包add
来说,它由函数innerFunction
和变量counter
组成,所以这时候add
是可以访问变量counter
的。
结论
所以闭包的功能就是使一个函数能访问另一个函数作用域中的变量。形成闭包之后,该变量不会被垃圾回收机制回收。
闭包的原理其实还是作用域。
知识扩展
什么是闭包
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
词法作用域
请看下面的代码:
function init() {
var name = "WebKaka"; // name 是一个被 init 创建的局部变量
function displayName() { // displayName() 是内部函数,一个闭包
console.log(name); // 使用了父函数中声明的变量
}
displayName();
}
init();
输出
init()
创建了一个局部变量 name
和一个名为 displayName()
的函数。displayName()
是定义在 init()
里的内部函数,并且仅在 init()
函数体内可用。请注意,displayName()
没有自己的局部变量。然而,因为它可以访问到外部函数的变量,所以 displayName()
可以使用父函数 init()
中声明的变量 name
。
运行该代码后发现, displayName()
函数内的 log()
语句成功显示出了变量 name
的值(该变量在其父函数中声明)。这个词法作用域的例子描述了分析器如何在函数嵌套的情况下解析变量名。词法(lexical)一词指的是,词法作用域根据源代码中声明变量的位置来确定该变量在何处可用。嵌套函数可访问声明于它们外部作用域的变量。
示例
现在来看以下例子 :
function makeFunc() {
var name = "WebKaka";
function displayName() {
console.log(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
输出
运行这段代码的效果和之前 init()
函数的示例完全一样。其中不同的地方(也是有意思的地方)在于内部函数 displayName()
在执行前,从外部函数返回。
第一眼看上去,也许不能直观地看出这段代码能够正常运行。在一些编程语言中,一个函数中的局部变量仅存在于此函数的执行期间。一旦 makeFunc()
执行完毕,你可能会认为 name
变量将不能再被访问。然而,因为代码仍按预期运行,所以在 JavaScript 中情况显然与此不同。
原因在于,JavaScript 中的函数会形成了闭包。 闭包是由函数以及声明该函数的词法环境组合而成的。该环境包含了这个闭包创建时作用域内的任何局部变量。在本例子中,myFunc
是执行 makeFunc
时创建的 displayName
函数实例的引用。displayName
的实例维持了一个对它的词法环境(变量 name
存在于其中)的引用。因此,当 myFunc
被调用时,变量 name
仍然可用,其值 WebKaka
就被传递到log
中。
相关文章
标签: 闭包
- 站长推荐