【JavaScript】一文了解JS的闭包

简介: 一文了解JS的闭包

🙉初识闭包

闭包可谓是JS的一大难点也是面试中常见的问题之一,今天开始梳理一下闭包的知识,请诸君品鉴。

🍇什么是闭包

闭包是嵌套的内部函数;内部函数包含被引用变量(函数)的对象。闭包存在于嵌套的内部函数中,例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来。当然如何直观的查看闭包可以通过chrome来查看,这里有个坑需要反馈一下,新版的chrome需要先调用fun2()才允许debugger,这样才能显示闭包。

<script>functionfn1(){
vara=2;
functionfn2(){//执行函数定义就会产生闭包(不用调用内部函数)console.log(a);
        }
//新版的chrome需要返回一下内部函数才会显示闭包returnfn2()
    }
fn1()
</script>

图片.png


🍈如何产生闭包

当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包

<script>// 将函数作为另一个函数的返回值functionfn1(){
vara=2;
functionfn2(){//a++;
console.log(a);
        }
returnfn2//将一个内部函数作为一个外部函数的返回值返回    }
varf=fn1()
//整个过程产生了一个闭包,主要看你产生了几个内部函数对象,调用了几次外部函数//闭包的特点就是函数内部的变量会一直存在于内存中,不会立即释放。f()//3   这里的f()是调用了内部函数f()//4</script>

图片.png

<script>// 将函数作为实参传递给另一个函数调用functionshowDelay(msg,time){
//setTimeout 的第一个参数是函数,符合闭包的规则setTimeout(function(){
alert(msg)
        },time)
    }
showDelay('张三',2000)
</script>

图片.png

🍉产生闭包条件

函数嵌套内部函数引用了外部函数的数据(变量/函数)

🍊闭包的作用

使用函数内部的变量在函数执行完毕后,仍然存活在内存中(延长了局部变量的生命周期);让函数外部可以操作(读写)到函数内部的数据(变量/函数)。

🍋闭包的生命周期

产生:在嵌套的内部函数定义执行完时就产生了(不是在调用),死亡:在嵌套的内部函数称为垃圾对象时就死亡了。

<script>functionfn1 () {
//此时闭包就已经产生了(函数提升,内部函数对象已经创建了)vara=2;
functionfn2 () {//a++;
console.log(a);
        }
returnfn2//将一个内部函数作为一个外部函数的返回值返回    }
varf=fn1()
f()//3   f()//4f=null//闭包死亡(包含闭包的函数对象成为垃圾对象)</script>

🍌闭包的应用

定义JS模块(具有特定功能的js文件),将所有的数据和功能都封装在一个函数的内部(私有的),只向外暴露一个包含n个方法的对象和函数;模块的使用者只需要通过模块暴露的对象调用方法来实现对应的功能。

//myModule.js 文件functionmyModule(){
// 私有数据varmsg='My Module'functionshowUpper(){
console.log('showUpper'+msg.toUpperCase());
    }
functionshowLow(){
console.log('showLow'+msg.toLowerCase());
    }
//向外暴露对象(给外部使用的方法)return {
showUpper:showUpper,
showLow:showLow    }
}
//index.html文件<scriptsrc="./myModule.js"></script><script>varmodule=myModule()
module.showUpper()
module.showLow()
</script>

图片.png

我们也可以通过匿名函数来实现闭包,这样能很便捷的调用闭包里面的属性,虽然会达到我们想要的效果,但是可能会造成全局的变量名污染,建议使用第一种。

//myModule2.js文件(function(){
// 私有数据varmsg='My Module'// 操作数据的函数functionshowUpper(){
console.log('showUpper'+msg.toUpperCase());
    }
functionshowLow(){
console.log('showLow'+msg.toLowerCase());
    }
//向外暴露对象(给外部使用的方法)window.myModule2= {
showUpper:showUpper,
showLow:showLow    }
})()
//index.js文件<scriptsrc="./myModule2.js"></script><script>myModule2.showUpper()
myModule2.showLow()
</script

图片.png

🍍闭包的缺点及解决方法

在我们使用闭包过程中,函数执行完后,函数内部的局部变量没有释放,占用内存时间会变长,容易造成内存泄漏,所以在日常开发中,尽量避免闭包的出现,或者要对局部变量及时释放。

<script>functionfn1(){
vararr=newArray[100000]
functionfn2(){
console.log(arr.length);
        }
returnfn2    }
varf=fn1()
f()
//不用闭包或者回收闭包f=null//让内部函数成为垃圾对象 --> 回收闭包</script>

内存溢出:一种程序运行出现的错误,当程序运行需要的内存超过了剩余的内存时,就会抛出内存溢出的错误。

<script>varobj= {}
for(vari=0;i<10000;i++){
obj[i]=newArray(1000000)
console.log('------');
    }
</script>

图片.png

内存泄漏:占用的内存没有及时释放,内存泄漏积累多了就容易导致内存溢出。常见的内存泄漏:意外的全局变量、没有及时清理的计时器或回调函数、闭包。

<script>//意外的全局变量functionfn(){
a=10;
console.log(a);
    }
// 调用函数虽然能打印a,但是a并没有被释放掉。一不注意就设置了一个全局变量fn()
//没有及时清理计时器或回调函数varintervalId=setInterval(function(){ //启动循环定时器后不清理console.log('--------');
    },2000)
// clearInterval(intervalId)//闭包functionfn1(){
vara=2//闭包 a 并没有被释放掉functionfn2(){
console.log(++a)
        }
returnfn2    }
varf=fn1()
f()
// f = null 不执行这条语句,a的值一直在</script>

🥭闭包案例

<script>// 案例一:varname="this is Window"varobject= {
name:"this is Object",
getName:function(){
returnfunction(){
returnthis.name            }
        }
    }
//闭包的this只能是全局,若在当前作用域中定义了this,就直接使用定义的this,若没定义,则需要一层层向外找,直到全局为止//本题是没有闭包的alert(object.getName()())//this is Window// 案例二:varname1="this is Window"varobject1= {
name1:"this is Object",
getName:function(){
//定义的that形成了闭包,内部函数引用了外部函数的变量,而this指向的是object,所以返回的是object中的name1varthat=this;
returnfunction(){
returnthat.name1            }
        }
    }
alert(object1.getName()())// this is Object</script>
<script>//没有使用闭包的话,数据是没有保留的,所以n传递给o之后,下次运算o值还是上次的值不会发生改变functionfun(n,o){
console.log(o);
return{
fun:function(m){
returnfun(m,n)
            }
        }
    }
//在执行fun(0)之后,n被之前的n=0,一直被调用vara=fun(0); //闭包里面的n传入了0a.fun(1); 
a.fun(2);
a.fun(3)//undefined,0,0,0//链式执行会导致n的改变,n是前面函数执行的形参varb=fun(0).fun(1).fun(2).fun(3)//undefined,0,1,2//c.fun(2)、c.fun(3)都调用了fun(1)留下的闭包nvarc=fun(0).fun(1); 
c.fun(2); 
c.fun(3)//undefined,0,1,1</script>


相关文章
|
4天前
|
自然语言处理 JavaScript 前端开发
Javascript中的闭包encloure
【10月更文挑战第1天】闭包是 JavaScript 中一种重要的概念,指函数能够访问其定义时的作用域内的变量,即使该函数在其词法作用域之外执行。闭包由函数及其词法环境组成。作用域链和词法作用域是闭包的核心原理。闭包常用于数据隐藏和封装,如模块模式;在异步操作中也广泛应用,如定时器和事件处理。然而,闭包也可能导致内存泄漏和变量共享问题,需谨慎使用。
|
17天前
|
JSON JavaScript 前端开发
JavaScript第五天(函数,this,严格模式,高阶函数,闭包,递归,正则,ES6)高级
JavaScript第五天(函数,this,严格模式,高阶函数,闭包,递归,正则,ES6)高级
|
8天前
|
缓存 JavaScript 前端开发
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
该文章详细讲解了JavaScript中的作用域、闭包概念及其应用场景,并简要分析了函数柯里化的使用。
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
|
10天前
|
JavaScript 前端开发
JavaScript 闭包
JavaScript 闭包
11 1
|
13天前
|
自然语言处理 前端开发 JavaScript
探索JavaScript中的闭包及其实际应用
本文深入探讨了JavaScript中闭包的概念、特性及其在实际项目中的应用。通过具体示例,详细讲解了闭包的创建方法和用途,揭示了闭包在数据保护和模块化开发中的重要性。同时,还讨论了闭包可能带来的内存管理问题及优化策略,为前端开发者提供了全面的闭包知识和实践指导。
|
22天前
|
自然语言处理 JavaScript 前端开发
探索JavaScript中的闭包:从基础概念到实际应用
本文深入探讨了JavaScript中闭包的概念,从定义、作用域链和实际应用等方面进行了详细阐述。通过生动的比喻和实例代码,帮助读者理解闭包在函数执行上下文中的重要性,以及如何在实际开发中有效利用闭包解决复杂问题。同时,文章也指出了过度使用闭包可能导致的潜在问题,并给出了相应的优化建议。
|
2月前
|
开发者 图形学 C#
深度解密:Unity游戏开发中的动画艺术——Mecanim状态机如何让游戏角色栩栩如生:从基础设置到高级状态切换的全面指南,助你打造流畅自然的游戏动画体验
【8月更文挑战第31天】Unity动画系统是游戏开发的关键部分,尤其适用于复杂角色动画。本文通过具体案例讲解Mecanim动画状态机的使用方法及原理。我们创建一个游戏角色并设计行走、奔跑和攻击动画,详细介绍动画状态机设置及脚本控制。首先导入动画资源并添加Animator组件,然后创建Animator Controller并设置状态间的转换条件。通过编写C#脚本(如PlayerMovement)控制动画状态切换,实现基于玩家输入的动画过渡。此方法不仅适用于游戏角色,还可用于任何需动态动画响应的对象,增强游戏的真实感与互动性。
58 0
|
2月前
|
Java 数据库连接 数据库
从零到精通:揭秘 Hibernate 构建持久层服务的全过程,你离数据持久化大师还有多远?
【8月更文挑战第31天】本文详细介绍了如何从零开始使用 Hibernate 构建一个持久层服务。首先,通过在 Maven 项目中添加必要的依赖,确保项目具备使用 Hibernate 的条件。接着,配置 `hibernate.cfg.xml` 文件以连接 MySQL 数据库,并设置了基本属性。然后定义了一个简单的 `User` 实体类及其映射关系。此外,还创建了一个 `HibernateUtil` 工具类来管理 `SessionFactory`。
28 0
|
2月前
|
自然语言处理 JavaScript 前端开发
|
2月前
|
缓存 JavaScript 前端开发
Vue.js与JavaScript性能优化终极揭秘:掌握这些技巧,让你的Web应用飞一般地流畅!
【8月更文挑战第30天】随着前端应用复杂度的增加,性能优化变得至关重要。本文深入探讨了如何利用Vue.js和JavaScript实现高效的应用性能。主要内容包括:优化组件设计以减少不必要的渲染,采用异步组件与懒加载技术加速应用启动,利用虚拟滚动和分页处理大数据集,改进Vuex使用方式以及合理运用浏览器缓存等策略。通过具体示例和最佳实践,帮助开发者充分挖掘Vue.js潜力,打造高性能的前端应用。
51 0