闭包(函数嵌套函数)

理解闭包前先要了解下变量的作用域,变量作用域主要分为两种,局部变量和全局变量。

局部变量只在函数体内被访问,全局变量在代码任何的地方都可以访问。

var a = 1   //全局变量

function fn(){
    console.log(a)    
}

fn()  //控制台输出4,因为a是全局变量,在任何地方都可以访问
function fn(){
     var a = 1     // 这里需要注意!在函数内部声明变量要使用var,否则声明的将会是一个全局变量
}
console.log(a)    //a is not defined  在函数内的a是局部变量,在fn()函数中才能被正确访问
声明变量的小插曲:ES6中新增了两种声明变量的方式,let和const 。

let声明的变量是没有变量提升的、块级作用域的本地变量,并且可选的将其初始化为一个值。

const声明的是常量,值无法改变改变,不能重新声明。

继续来说闭包,但是在上面的代码中如果想访问函数内部的变量呢?此时就可以用到闭包了

function fn(){
    var a = 1    //局部变量,函数fn外部并不能访问
    function fn1(){    
        console.log(a)  //可以访问到fn函数中变量a,也就是函数内部可以读取到外部的变量,反之不行
    }
     return fn1
}

 var result = fn()  //调用fn会返回一整个fn1的函数体,把函数体赋值给result,再进行调用

 result() // 控制台输出1


那么在fn1()函数中为什么可以访问到a?
是因为JavaScript中处理变量和函数的作用域的机制:链式作用域(Chain Scope)
它允许在代码的多个部分中访问和操作变量,无需显式地传递变量或使用全局作用域
变量和函数的作用域可以沿着一条链路进行查找和访问
这条链路通常由闭包(Closure)和原型链(Prototype Chain)组成。

所以闭包就是能够读取其他函数内部变量的函数。也是连接函数内部函数外部之间的纽带。

说完闭包的概念后,那么在哪些地方可以得到实际运用呢?来说说用途。

1.可以读取函数内部的变量

2.让这些变量的值始终保持在内存中

3.代替全局变量:全局变量可能会在程序中的多个地方被修改,使用闭包可以限制变量的可见性,避免不必要的全局变量污染

以下几个代码片段可以看到闭包的用途:

// 避免使用全局变量  
function createCounter() {  
  let count = 0; // 私有变量  
  
  return {  
    increment: function() { // 公开方法,可以访问和修改私有变量  
      count++;  
    },  
    getCurrentCount: function() { // 另一个公开方法,返回当前计数器的值  
      return count;  
    }  
  };  
}  
  
// 使用闭包创建计数器对象  
var counter = createCounter();  
counter.increment(); // 计数器增加1  
console.log(counter.getCurrentCount()); // 输出1
1  var name = "The Window";
2
3  var object = {
4    name : "My Object",
5
6    getNameFunc : function(){
7      return function(){
8        return this.name;
9      };
10
11    }
12
13  };
14
15  console.log(object.getNameFunc()());

//此时控制台应输出"The Window"
在这段代码中,getNameFunc函数是object对象的一个方法,它返回了一个内部函数
但是,这个内部函数是在全局作用域中创建的,而不是在getNameFunc函数的上下文中创建的。
因此,当这个内部函数被调用时,它的上下文是全局对象,this指向window,而不是object对象。

1  var name = "The Window";
2
3  var object = {
4    name : "My Object",
5
6    getNameFunc : function(){
7      var that = this;
8      return function(){
9        return that.name;
10      };
11
12    }
13
14  };
15
16  alert(object.getNameFunc()());

//控制台输出"My Object"
执行object.getNameFunc()时,this指向window
但var that = this,that保存的是其父级(object)的this
因此调用that.name时,则输出"My Object"

闭包也不是想用就用的,需要注意以下几点:

1.闭包会使函数中的变量都保存在内存中,消耗大,不能滥用,否则会造成网页的性能问题,导致内存泄露。可以在退出函数前将其置空null。

2.闭包可以访问外部变量的私有属性,但是不建议过度依赖闭包来访问私有属性,这样会使代码难以维护和扩展、难以调试。

3.在使用闭包时要注意避免改变外部变量的值,因为这可能会对其他代码产生意想不到的影响。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值