闭包:什么是闭包、闭包的作用、闭包的解决

这是我最烦的东西,没有之一!一万头草泥马狂奔而过!

说明

  • 在JS中,函数可以赋值给一个变量,而JS又是弱类型语言,所以在JS中函数就可以作为参数或者是返回值。
  • 什么是闭包?函数嵌套函数,并且内层函数作为返回值,引用外部函数的参数或变量。
  • 闭包在vue项目中的使用?

 学习闭包我们要清楚函数作用域、内存回收机制、作用域继承。

1、什么是闭包 

1.1 函数作用域

作用域我们可以认为它是一个封闭的盒子,只让它在这个盒子里面进行操作,也可以称这个盒子为独立作用域。在js中,一个函数要执行时就会在内存里面创建一个独立作用域————封闭的盒子。

比如在函数中第一一个变量,只能在函数这个独立作用域中使用(也就是封闭的盒子)。只要跳出这个作用域,就找不到该变量了。

而且函数执行完毕之后,这个独立作用域或(封闭的盒子)就会删除。有一种情况下这个封闭的盒子是不会删除的,那就是“闭包”,后面会讲到。

1.2 内存回收机制

内存回收机制就是不在用到的内存空间,系统会自动进行清理出空间提供给其他程序使用。那回收的前提是什么呢?

内部函数引用外部的函数的变量,外部函数执行完毕,作用域也不会删除。从而形成了一种不删除的独立作用域。

某一个变量或者对象被引用,因此在回收的时候不会释放它,因为被引用代表着被使用,回收机制不会对正在引用的变量或对象进行回收的。

1.3 作用继承

所谓的作用域继承,就像是儿子可以继承父亲的财产一样。比如我这里有一个大的盒子作为一个父级的作用域,然后在这个大的盒子里边放一个小的盒子,作为子作用域。我们规定可以在小盒子中获取到大盒子中的东西,大盒子不能获取小盒子里的东西就称为作用域继承。

在 JS 中,道理是一样的,在一个函数里边我们再声明一个函数,内部函数可以访问外部函数作用域的变量,而外部的函数不能获取到内部函数的作用域变量。

那好,上边的这几个概念理解了之后,什么是闭包对你来说已经不是什么问题。

什么是闭包,那就是在一个函数里边再定义一个函数。这个内部函数一直保持有对外部函数中作用域的访问(小盒子可以一直访问大盒子但大盒子不能访问小盒子)。

函数执行,形成一个独立作用域,保护里边的私有变量不受外界的干扰,除了保护私有变量外,还可以存储一些内容,这样的模式叫做闭包。

2、闭包的作用是什么

闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

作用是:通过一系方法,将函数内部的变量(局部变量)转化为全局变量

3、闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。 

function f1(){
 var n=999;
 nAdd=function(){
    alert(n+=1);  
  }
 function f2(){
    alert(n);
  }
 return f2;
}
var result=f1();
result(); //999
nAdd();//1000
result(); //1000

在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

这段代码中另一个值得注意的地方,就是"nAdd=function(){n+=1}"这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。 其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个操控者,可以在函数外部对函数内部的局部变量进行操作。

4、使用闭包的注意点

1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。

2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

使用一

function f1() {
           var a = 0;
           return function () {
               return a+5;
           }
        }

var f=f1();
console.log(f);
//打印结果:打印出来一个函数,而且正好是内层函数
ƒ () {
return a+5;
}

console.log(f());
//打印结果:5

 

 使用二

如果我们碰到这样的例子,我们记住一点,外层函数只要不被调用第二次,那么外层函数的参数或者变量的值就不会被冲刷,也就是说对于内层函数而言,外层函数的变量可以看成“全局变量”。

function f2() {
            var a = 0;
            return function () {
                return a++;//a++称为“后增量”,++a称为“前增量”
            }
        }
        f=f2();
        console.log(f());
        console.log(f());
        console.log(f());
        f=f2();
        console.log(f());
        console.log(f());
        console.log(f());

输出结果为:
0
1
2
0
1
2

例子三

function f3() {
            var a = 0;
            return function () {
                return ++a;
            }
        }

        console.log(f3()());
        console.log(f3()());
        console.log(f3()());
打印结果:

1
1
1

这个例子我们直接用图解来看一下:在这里插入图片描述

 这个不就相当于外层函数调用了3次,所以a也被重置成0三次。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BMG-Princess

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值