理解javascript闭包

简介: 原文:理解javascript闭包1.闭包是什么 官方解释:闭包是一个拥有很多变量和绑定了这些变量的环境的表达式(其实就是函数),因而这些变量也是该表达式的一部分。这个定义虽然太学术,但是告诉我们两个信息: 1)闭包是一个函数 2)函数中有很多变量 上面两个是构成闭包的两个主要条件。
原文: 理解javascript闭包

1.闭包是什么

官方解释:闭包是一个拥有很多变量和绑定了这些变量的环境的表达式(其实就是函数),因而这些变量也是该表达式的一部分。这个定义虽然太学术,但是告诉我们两个信息:

1)闭包是一个函数

2)函数中有很多变量

上面两个是构成闭包的两个主要条件。

下面我们用通俗的话来解释一下:js中的所有函数都是闭包(因为函数中的局部变量只能函数内部访问),但是嵌套函数产生的闭包更加强大,也是我们现在所探讨的闭包。

如果上面的解释还不够通俗,下面的终极解释我想你一定能够看懂:

有一个函数a,函数a中嵌套了一个函数b,如果函数b被函数a外部的一个变量引用,就创建了一个闭包。

下面我们来看看具体如何通过代码来创建闭包,以加深上面概念的理解。

2.创建闭包

在创建闭包之前,首先要明白两个概念,一个是变量的作用域,一个事js中的作用域链,第一点我们简单说一下,第二点自己去查资料。

在Js中变量根据作用域的不同可以分为全局变量和局部变量(事实上很多语言都是这样),在js中,如果一个变量没有定义在任何函数中,则为全局变量;相对应的,定义在函数中的变量就是局部变量,但是如果函数中变量在声明时没有使用var关键字,则其仍然会称为全局变量。我们来看例子。

 

function f() {
            a = 1;//没有使用var,所以在函数外部也可以访问
        }
        f();
        alert(a);

  

下面我们看看如何创建闭包,看下面的函数

 

 

     function f1() {
            var a = 10;
            a++;
            alert(a);
        }
        var func1 = f1();
        func1;
        func1;

 

希望你能猜对上面代码的运行结果,只输出一个11。在函数f1的外部创建了变量func1,然后指向由函数f1的构造函数创建的对象。(在js中,你可以将函数看作是类,)。当执行完代码func1之后,这个对象就没有引用了,所以会被垃圾回收,对象中的变量a同样也会被回收;所以当再次执行func1时就不会有输出了。

 

从上面的代码,希望你能明白这样一个道理:js中是有垃圾回收机制的。当一个对象没有变量引用的时候,这个对象就会被回收。

再来看下面的代码:

 

function f1() {
            var a = 10;
            function f2() {
                a++;
                alert(a);
            }
            return f2;
        }
        var func1 = f1();
        func1();
        func1();

  

上面代码的输出结果为11,12。

 

执行完第一句func1()之后,对象应该被回收,第二句func1();应该没有输出猜对呢,这是为什么呢?

我们来分析一下。

首先看var func1=f1();这行代码执行之后,func1是什么。在函数f1中返回的是函数f2,所以func1的值其实是函数f2。按理说当执行完这行代码之后,函数f1的使命已经完成,应该被垃圾回收才是,你们变量a也会被清除,但是执行代码func1()之后的结果居然为11,这说明函数f1中的变量a没有被清除,那么肯定函数f1也没有被垃圾回收。这是为什么?

我们前面说过,一个对象如果被垃圾回收的条件是什么,那就是没有变量引用这个对象。我们来看看上面的代码。函数f2中对函数f1中的变量a进行++操作,也就是说在函数f2中引用了函数f1中的变量,也就是函数f2引用了函数f1。而代码var func1=f1();其实是将函数f2返回给变量func1,也就是说变量func1引用了函数f2,而函数f2由引用了函数f1,这种间接引用的结果就是函数f1一直被变量引用着,所以一直无法被垃圾回收。

上面的情况就是闭包,我们再回顾一下闭包的定义:如果函数a中的嵌套函数b被函数a外部的变量引用,就创建了闭包。

综合上面的讨论,我们可以看出闭包的作用是什么

3.闭包的作用

1)变量的安全性:我们无法在函数f1的外部直接访问其局部变量a,只能通过函数f2来访问,而在函数f2中我们可以写代码进行安全性的控制,这是不是和c#中类的属性很像。所以我们可以将函数f2看成是函数f1的一个属性,这个属性只有setter方法,而将局部变量a看成是函数f1的私有字段,只能通过公共属性f2才能访问f1中的私有字段a。

2)让变量的值始终保存在内存中。这个已经非常清晰了,通过闭包,函数f1中的变量a没有被回收,而是一直保存在内存中。

目录
相关文章
|
3月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
2月前
|
JavaScript 前端开发
js 闭包的优点和缺点
【10月更文挑战第27天】JavaScript闭包是一把双刃剑,在合理使用的情况下,它可以带来很多好处,如实现数据封装、记忆功能和模块化等;但如果不注意其缺点,如内存泄漏、变量共享和性能开销等问题,可能会导致代码出现难以调试的错误和性能问题。因此,在使用闭包时,需要谨慎权衡其优缺点,根据具体的应用场景合理地运用闭包。
128 58
|
2月前
|
缓存 JavaScript 前端开发
js 闭包
【10月更文挑战第27天】JavaScript闭包是一种强大的特性,它可以用于实现数据隐藏、记忆和缓存等功能,但在使用时也需要注意内存泄漏和变量共享等问题,以确保代码的质量和性能。
46 7
|
2月前
|
自然语言处理 JavaScript 前端开发
JavaScript闭包:解锁编程潜能,释放你的创造力
【10月更文挑战第25天】本文深入探讨了JavaScript中的闭包,包括其基本概念、创建方法和实践应用。闭包允许函数访问其定义时的作用域链,常用于数据封装、函数柯里化和模块化编程。文章还提供了闭包的最佳实践,帮助读者更好地理解和使用这一强大特性。
28 2
|
2月前
|
存储 缓存 自然语言处理
掌握JavaScript闭包,提升代码质量与性能
掌握JavaScript闭包,提升代码质量与性能
|
2月前
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包(Closures)
深入理解JavaScript中的闭包(Closures)
|
2月前
|
存储 自然语言处理 JavaScript
深入理解JavaScript的闭包(Closures)
深入理解JavaScript的闭包(Closures)
41 0
|
3月前
|
设计模式 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
在本文中,我们将深入探讨JavaScript中的一个重要概念——闭包。闭包是一种强大的编程工具,它允许函数记住并访问其所在作用域的变量,即使该函数在其作用域之外被调用。通过详细解析闭包的定义、创建方法以及实际应用场景,本文旨在帮助读者不仅理解闭包的理论概念,还能在实际开发中灵活运用这一技巧。
|
3月前
|
缓存 JavaScript 前端开发
深入了解JavaScript的闭包:概念与应用
【10月更文挑战第8天】深入了解JavaScript的闭包:概念与应用
|
3月前
|
自然语言处理 JavaScript 前端开发
Javascript中的闭包encloure
【10月更文挑战第1天】闭包是 JavaScript 中一种重要的概念,指函数能够访问其定义时的作用域内的变量,即使该函数在其词法作用域之外执行。闭包由函数及其词法环境组成。作用域链和词法作用域是闭包的核心原理。闭包常用于数据隐藏和封装,如模块模式;在异步操作中也广泛应用,如定时器和事件处理。然而,闭包也可能导致内存泄漏和变量共享问题,需谨慎使用。