草庐IT

闭包

Liu-h 2023-12-18 原文

闭包理解

如何产生闭包

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

闭包是什么

  • 使用chrome调试查看

  • 理解一 -- 闭包是嵌套的内部函数

  • 理解二 -- 闭包是包含被引用变量(函数)的对象

  • 闭包存在于嵌套的内部函数中

  • 产生闭包的条件

  • 函数嵌套

  • 内部函数引用了外部函数的数据(变量或函数)

<script>
    function fn1() {
        var a = 3;
        function fn2() {
            console.log(a);
        }
        fn2();
    }
    fn1();
</script>

常见闭包

将函数作为另一个函数的返回值

function fn1() {
    var a = 2;
    function fn2() {
        a++;
        console.log(a);
    }
    return fn2;
}
var f = fn1();
f();    //3--fn1的返回值是fn2--相当于调用了fn2()--相当于fn1()()
f();    //4--闭包不会消失--第一次fn1()执行时--闭包内的数据是3--第二次执行时就是4

将函数作为实参传递给另一个函数调用

function showDelay(msg, time) {
    setTimeout(function () {
        console.log(msg);   //闭包
    }, time);
}
showDelay('zao', 2000);

闭包的作用

  • 使用函数内部的变量在函数执行完后--仍然存活在内存中--延长了局部变量的生命周期

  • 让函数外部可以操作(读写)到函数内部的数据--变量/函数

问题

  • 函数执行完--函数内部声明的局部变量是否还存在--一般不存在,存在于闭包中的变量才可能存在
  • 在函数外部能直接访问函数内部的局部变量吗--不能,但可以通过闭包让外部操作它

闭包的生命周期

  • 产生--在嵌套内部函数定义执行完时就产生了
  • 死亡--在嵌套内部函数成为垃圾对象时
function fn1(){
    // 闭包产生--函数提升--内部函数已经创建了
    var a = 2;
    function fn2(){
        a++;
        console.log(a);
    }
    return fn2;
}
//只要有变量引用fn1()闭包就一直存在
var f = fn1();
f();
f();
//闭包死亡--包含闭包的函数成为垃圾对象
f = null;

闭包的应用

定义JS模块

  • 具有特定功能的js文件
  • 将所有数据和功能都封装在一个函数内部--私有
  • 只向外暴露一个包含n个方法的对象或函数
  • 模块的使用者--只需通过模块暴露的对象调用方法来实现对应的功能
//JS文件
function myMoudle() {
    var msg = 'zaoya';
    function doSomething() {
        //toUpperCase--字符串转换为大写
        console.log('doSomething()' + msg.toUpperCase());
    }
    function doOtherthing() {
        //toLowerCase--字符串转换为小写
        console.log('doOtherthing()' + msg.toLowerCase());
    }
    //向外暴露对象
    return {
        doSomething: doSomething,
        doOtherthing: doOtherthing
    }
}

//html文件
<script src="myMoudle.js"></script>
<script>
    let fn = myMoudle();
	fn.doSomething();
	fn.doOtherthing();
</script>
//JS文件
(function myMoudle1() {
    let msg = 'zaozao';
    function doSomething() {
        console.log('doSomething()' + msg.toUpperCase);
    };
    function doOtherthing() {
        console.log('doOtherthing()' + msg.toLowerCase);
    }
    window.myMoudle1 = {
        doSomething: doSomething,
        doOtherthing: doOtherthing
    }
})()

//html文件
<script src="myMoudle1.js"></script>
<script>
	myMoudle1.doSomething();
	myMoudle1.doOtherthing();
</script>

闭包的缺点

缺点

  • 函数执行完后--函数内的局部变量没有释放--占用内存时间会变长
  • 容易造成内存泄漏

解决

  • 能不用闭包就不用闭包
  • 及时释放

内存溢出

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

内存泄漏

  • 占用的内存没有及时释放
  • 内存泄漏积累多了就容易导致内存溢出

常见内存泄漏

  • 意外的全局变量
  • 没有及时清理的计时器或回调函数
  • 闭包

面试题

var name = 'The Window';
var object = {
    name: 'My Object',
    getNameFunc: function () {
        return function () {
            return this.name;
        }
    }
}
//object.getNameFunc()--是对象调用--通过object调用--this为object
//通过object.getNameFunc()--调用函数--object.getNameFunc()()--是函数调用--this为window
alert(object.getNameFunc()());  //The Window
var name2 = 'The Window';
var object = {
    name2: 'My Object',
           var that = this;
        return function () {
            return that.name2;
        }
    }
}
//object.getNameFunc()--是对象调用--通过object调用--this为object
//object.getNameFunc()()--中that是object.getNameFunc()的this--指向object
alert(object.getNameFunc()())       //My Object

有关闭包的更多相关文章

  1. ruby - Ruby 中的闭包和 for 循环 - 2

    我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对

  2. ruby - 如何 `break` 闭包中的外部循环(Proc,lambda)? - 2

    loop{break}可以正常工作,但是block=Proc.new{break}#or#block=lambda{break}loop(&block)#=>LocalJumpError:breakfromproc-closure是否可以在block变量中中断?更新:举例说明:defodd_loopi=1loopdoyieldii+=2endenddefeven_loopi=2loopdoyieldii+=2endend#Thisworkodd_loopdo|i|putsibreakifi>10end#Thisdoesn'tworkbreak_greater_10=Proc.newdo

  3. ruby - 在 Ruby 中定义一个闭包方法 - 2

    我正在用ruby​​重新定义对象中的方法,我需要新方法作为闭包。例如:defmess_it_up(o)x="blahblah"defo.to_sputsx#Wrong!xdoesn'texistshere,amethodisnotaclosureendend现在如果我定义一个Proc,它就是一个闭包:defmess_it_up(o)x="blahblah"xp=Proc.new{||putsx#Thisworksend#buthowdoIsetittoo.to_s.defo.to_sxp.call#sameproblemasbeforeendend有什么想法吗?谢谢。

  4. ruby - Ruby 中的闭包 - 2

    我在闭包方面遇到了一些麻烦,我想知道是什么规范的make-adder过程的等效代码将在ruby。在计划中它会是这样的:(define(make-addern)(lambda(x)(+xn)) 最佳答案 其实很接近...defmake_addrnlambda{|x|x+n}endt=make_addr100t.call1101在1.9中你可以使用...defmake_addrn->(x){x+n}end 关于ruby-Ruby中的闭包,我们在StackOverflow上找到一个类似的问题:

  5. javascript - "return () => local;"在这个闭包中做了什么? - 2

    我正在通过阅读“EloquentJavascript”学习javascript,但对第3章(函数)中的“闭包”部分感到困惑。在前面的部分中,我了解了箭头函数,以及如何将它们用作匿名函数。我最初的想法是,这是一个匿名函数示例,我只是还不熟悉。特别是,我对“()=>local”对返回/返回的作用感到困惑。functionwrapValue(n){letlocal=n;return()=>local;}letwrap1=wrapValue(1);letwrap2=wrapValue(2);console.log(wrap1());//→1console.log(wrap2());//→2这是

  6. JavaScript 闭包 - 使用 ECMA 规范,请解释闭包是如何创建和维护的 - 2

    我正在阅读JavaScriptclosures.我熟悉ExecutionContexts,如何LexicalEnvironment维护的,很熟悉LexicalScoping.我想知道JavaScript中的闭包是如何创建和维护的。有时,如果不了解它的实际操作方式,我很难掌握如此重要的概念。我知道,根据维基百科,闭包是isafunctionorreferencetoafunctiontogetherwithareferencingenvironment—atablestoringareferencetoeachofthenon-localvariables(alsocalledfreev

  7. javascript - 防止 JavaScript 闭包继承作用域 - 2

    我正在寻找一种奇特的方法来防止闭包继承周围的范围。例如:letfoo=function(t){letx='y';t.bar=function(){console.log(x);//=>'y'});};我只知道两种方法来阻止共享范围:(1)使用影子变量:letfoo=function(t){letx='y';t.bar=function(x){console.log(x);//=>'?'});};(2)把函数体放在别处:letfoo=function(t){letx='y';t.bar=createBar();};我的问题是-有谁知道防止闭包继承JS范围的第三种方法吗?花哨的东西很好。我

  8. 闭包中的 javascript 原型(prototype)和 "this"访问 - 2

    我是js新手,对下面的代码很疑惑:Foo=function(arg){this.arg=arg;};Foo.prototype={init:function(){varf=function(){alert("currentarg:"+this.arg);//amexpecting"bar",gotundefined}f();}};varyo=Foo("bar");yo.init();我应该得到“currentarg:bar”,但得到的是“currentarg:undefined”。我注意到首先将this.arg复制到一个“普通”变量中,然后在闭包中引用这个变量:Foo.prototyp

  9. javascript - 使用闭包编译器进行类型检查不是隐式的吗? - 2

    我正在编译文件并获得可运行的编译代码,但注释似乎被完全忽略了;没有警告没有错误。使用calcdeps.py通过以下命令编译我的代码:setcalc="D:\software\closurecompiler\library\closure\bin\calcdeps.py"c:\Python27\python.exe%calc%^--pathD:\flex_sdk_4.6\projects\EnglishConverter\bin\js\^--inputD:\flex_sdk_4.6\projects\EnglishConverter\bin\js\mmt\Mediator.js^--in

  10. javascript - 构造函数与闭包? - 2

    这2个对象a使用构造函数创建,b使用闭包创建,究竟有什么不同?属性__proto__是否对使用闭包无法实现的任何事情有用?我应该在不同的情况下使用这些技术吗?内存使用有区别吗?(jsFiddle)window.MODULE={};MODULE.constructor=function(){this.publicVariable=10;};MODULE.constructor.prototype.publicMethod=function(){returnthis.publicVariable;};//-------------------------------//MODULE.clo

随机推荐