【前端面试系列】JS中的闭包-来龙去脉

本文深入探讨JavaScript中的闭包概念,解析闭包如何帮助解决计数器等常见问题,并通过实例展示闭包的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

经历过面试的前端人被问得做多的一个话题或许就是js的闭包了吧,就好像高考中总要出些难题来拉开不同人的差距,而闭包就是如此,哪怕平时用的不多,但是因为其特殊性总被拿来衡量一个前端人的js掌握情况。
以前也陆陆续续看过不少资料,书籍,对其的解释五码八门,大差不差,但从来无法回答自己几个核心问题(例如为啥叫closure,到底使用场景是什么),所以一直无法深入去理解,也就更别提灵活的使用了。
最近查阅资料时发现w3school中对其的介绍颇为深入,翻译给大家,希望对大家有所启迪和帮助。

资源地址:https://www.w3schools.com/js/js_function_closures.asp

w3school不清楚原因被墙了,明显纯技术的网站

js中的变量可以是属于local的或是全局global的。global变量可以利用closure闭包技术变成local本地的。

全局变量

一个函数可以获取函数内部所有的变量,就像下面这样(感觉像废话)

Example
function myFunction() {
    var a = 4;
    return a * a;
}

但函数通过可以获取外面定义的变量(js特色):

Example
var a = 4;
function myFunction() {
    return a * a;
}

在上一个例子中,a是一个全局的变量。在一个网页中,全局变量属于window对象。当然了,全局变量可以在页面的所有脚本中被使用和修改。在第一个例子中,a是一个局部变量。一个局部变量只能被用在函数定义的地方,对于其他函数和脚本是隔离的。

全局变量和局部变量就算名字取得一样了,还是不同的变量,改变其中一个,另一个不受影响。

如果变量创建的时候是不带关键字var的,那就都是全局变量,哪怕他们是在函数内部的定义的。

变量的生命周期

全局变量存活的时间就是应用(可以是window或是你的网页)存在的时间。局部变量生命可就更短了,在幻术被调用的时候创建,然后在函数结束的时候被删除掉。

A Counter Dilemma(计数器的悖论)

翻译的不好,其实不是悖论,更确切的说是一种两难的境地,没有好的办法来处理这个计数器,当然后面得通过闭包来实现

假定你想要借助某个变量来统计某些东西,而且你希望所有的函数都可以使用这个。你当然可以使用一个全局变量和一个函数来实现上面的需求:

Example
// Initiate counter
var counter = 0;

// Function to increment counter
function add() {
    counter += 1;
}

// Call add() 3 times
add();
add();
add();

// The counter should now be 3

上面的方案存在一个问题,页面上的代码可以直接修改这个全局变量counter,而且不需要调用add(而我们希望的是counter只作为add的私有变量来处理)

Example
// Initiate counter
var counter = 0;

// Function to increment counter
function add() {
    var counter; 
    counter += 1;
}

// Call add() 3 times
add();
add();
add();

//The counter should now be 3. But it is 0

完全不起作用,因为我们显示的是全局变量的counter而不是局部的counter。我们可以通过让函数返回它来使删除全局变量counter而只访问局部的counter。

Example
// Function to increment counter
function add() {
    var counter; 
    counter += 1;
    return counter;
}

// Call add() 3 times
add();
add();
add();

//The counter should now be 3. But it is 1.

还是不起作用,因为我们在每次调用函数的时候都重置了局部变量counter。而一个js的内部函数就可以解决这个问题。

JS嵌套函数

所有的函数都可以访问全局的作用域。事实上,在js中,所有的函数都可以访问父域的变量。JS支持嵌套函数,嵌套函数就可以访问父域。在下面的例子中,内部函数plus()可以在父函数中访问counter变量。

Example
function add() {
    var counter = 0;
    function plus() {counter += 1;}
    plus();    
    return counter; 
}

这可以解决counter的两难情况,只要我们可以在外部获取到plus函数。我们需要让counter=0只执行一次。因此我们需要closure,闭包。

JS闭包

还记得自调用函数么,来看看下面的函数:

Example
var add = (function () {
    var counter = 0;
    return function () {counter += 1; return counter}
})();

add();
add();
add();

// the counter is now 3

变量add 设置了自调用函数来返回一个函数。自调用函数正好只执行一次,实现了counter的初始化。这就是一个js的闭包,它能够让一个函数有自己私有的变量。counter的作用域被限制在匿名函数中,而且只能通过add函数来改变。所以说闭包就是一个能够获取父域的函数,即使父函数已经关了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值