浅谈js闭包理解

news/2024/7/10 23:11:17 标签: javascript, js, es6

js_0">清晰理解js闭包

我们都知道,js的作用域分两种,全局和局部,基于我们所熟悉的作用域链相关知识,我们知道在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得当前包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的,那么我们想在一个函数内部也有限权访问另一个函数内部的变量该怎么办呢?闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。

我们首先知道闭包有3个特性:

①函数嵌套函数

②函数内部可以引用函数外部的参数和变量

③参数和变量不会被垃圾回收机制回收

本文我们以闭包两种的主要形式来学习

①函数作为返回值

javascript">function a() {
        var name = "dov"
        return function () {
            return name
        }
    }
    var b = a()
    console.log(b())

在这段代码中,a()中的返回值是一个匿名函数,这个函数在a()作用域内部,所以它可以获取a()作用域下变量name的值,将这个值作为返回值赋给全局作用域下的变量b,实现了在全局变量下获取到局部变量中的变量的值

再来看一个闭包的经典例子
javascript">function fn(){
        var num = 3
        return function(){
            var n = 0
            console.log(++n)
            console.log(++num)
        }
    }
    var fn1 = fn()
    fn1() //1  4
    fn1() //1  5

一般情况下,在函数fn执行完后,就应该连同它里面的变量一同被销毁,但是在这个例子中,匿名函数作为fn的返回值被赋值给了fn1,这时候相当于fn1=function(){var n = 0 … },并且匿名函数内部引用着fn里的变量num,所以变量num无法被销毁,而变量n是每次被调用时新创建的,所以每次fn1执行完后它就把属于自己的变量连同自己一起销毁,于是乎最后就剩下孤零零的num,于是这里就产生了内存消耗的问题

再来看一个经典例子-定时器与闭包

写一个for循环,让它按顺序打印出当前循环次数

javascript"> for(var i =0 ;i < 5;i++){
        setTimeout(function(){
            console.log(1+"  ")

        },100)
    }

按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout可以执行的时候,for循环已经结束,i的值也已经编程5,所以打印出来五个5,那么我们为了实现预期结果应该怎么改这段代码呢?(ps:如果把for循环里面的var变成let,也能实现预期结果)

引入闭包来保存变量i,将setTimeout放入立即执行函数中,将for循环中的循环值i作为参数传递,100毫秒后同时打印出1 2 3 4 5

那如果我们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?



在这段代码中,相当于同时启动3个定时器,i*100是为4个定时器分别设置了不同的时间,同时启动,但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果。

②闭包作为参数传递

总结一下闭包好坏处

好处

① 保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突

② 在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)

③ 匿名自执行函数可以减少内存消耗

坏处

① 其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;

② 其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

↓↓↓ 个人写的一个公众号,还在完善中 ,欢迎加入↓↓↓ | ᴥ•́ )✧ ↓↓↓

在这里插入图片描述


http://www.niftyadmin.cn/n/1728111.html

相关文章

随机森林RF原理总结

在集成学习原理中知道&#xff0c;集成学习分为两部分Bagging和Boosting。随机森林RF作为Bagging方法的典型例子&#xff0c;以其并行训练的优点在如今处理数据问题上广受欢迎。随机森林&#xff0c;顾名思义&#xff0c;是有多棵树组成的森林&#xff0c;故RF的弱学习器都是决…

js深拷贝与浅拷贝

关于js深浅拷贝 如何区分深拷贝与浅拷贝&#xff0c;简单点来说&#xff0c;就是假设B复制了A&#xff0c;当修改A时&#xff0c;看B是否会发生变化&#xff0c;如果B也跟着变了&#xff0c;说明这是浅拷贝&#xff0c;拿人手短&#xff0c;如果B没变&#xff0c;那就是深拷贝…

贝叶斯优化调参-Bayesian optimiazation原理加实践

随着机器学习用来处理大量数据被广泛使用&#xff0c;超参数调优所需要的空间和过程越来越复杂。传统的网格搜索和随即搜索已经不能满足用户的需求&#xff0c;因此方便快捷的贝叶斯优化调参越来越受程序员青睐。 1.贝叶斯优化原理介绍 贝叶斯优化用于机器学习调参由J. Snoek…

wepy框架的this绑定数据页面不重新渲染更新的解决办法

问题分析来源&#xff1a;数据绑定:data{title: i am old tilte } 1.在wepy中当单独设置this.title i am new title,页面数据没有更新.2.如果单独设置this.setData({title: i am new title})页面数据更新了,但是切换页面回来数据还是旧的.3.如果先设置this.setData({title: i …

GBRT原理介绍

GBDT有很多简称&#xff0c;有GBT&#xff08;Gradient Boosting Tree&#xff09;, GTB&#xff08;Gradient Tree Boosting &#xff09;&#xff0c; GBRT&#xff08;Gradient Boosting Regression Tree&#xff09;, MART(Multiple Additive Regression Tree)&#xff0c;…

Windows上python读取grib2文件(不用Linux)

最近在网上下载的NCEP的fnl数据&#xff0c;发现只有grib2文件格式。因为现在处理数据使用的更多的是python&#xff0c;matlab一类的。网上一搜python读取grib文件需要依赖pygrib库&#xff0c;pygrib是欧洲中期天气预报中心(ECMWF)的GRIG API C库的Python接口&#xff0c;通过…

小程序不在合法域名列表中

一&#xff1a;报错截图 二、检查原因 出现这种报错的原因大概有以下几点&#xff1a; &#xff08;1&#xff09;、wx.request发起的是 HTTPS 请求 &#xff08;2&#xff09;、客户端的 HTTPS TLS 版本为1.2&#xff0c;但 Android 的部分机型还未支持 TLS 1.2&#xff0c…

Flink筛选重要配置参数

1.简单介绍一下flink背景 随着科技的发展&#xff0c;大数据框架处理海量数据越来越流行。有状态流计算将会逐步成为企业作为构建数据平台的架构模式&#xff0c;而目前从社区来看&#xff0c;能够满足的只有Apache Flink。Flink通过实现Goolge Dataflow流式计算模型实现了高吞…