JavaScript——闭包函数及拓展题目

 2023-09-11 阅读 24 评论 0

摘要:文章目录问题引入一、闭包函数1.什么是闭包函数?2.步骤3. 何时使用4.代码结构二、示例图解如果要直接看结论,可跳过此处图解,直接看“三”三、简化记忆四、缺点五、拓展题目1.多次生孩子情况2.双胞胎情况六、技巧 问题引入 假设现在要设计一段程序ÿ

文章目录

  • 问题引入
  • 一、闭包函数
    • 1.什么是闭包函数?
    • 2.步骤
    • 3. 何时使用
    • 4.代码结构
  • 二、示例图解
          • 如果要直接看结论,可跳过此处图解,直接看“三”
  • 三、简化记忆
  • 四、缺点
  • 五、拓展题目
    • 1.多次生孩子情况
    • 2.双胞胎情况
  • 六、技巧

问题引入

假设现在要设计一段程序,给出金钱总数,每使用一次钱就会在总数里扣除:

  • 全局变量
    a.优点:重用
    b.缺点:极其被污染、篡改
var total=1000;function pay(money){total-=money;console.log(`花了${money},还剩${total}`);
}
pay(100);
pay(100);

结果正确,但是使用了全局变量,容易造成污染:
在这里插入图片描述

  • 局部变量
    a.优点:不会被污染
    b.缺点:不可重用

函数题目和答案解析、那如果我们使用局部变量呢?

function pay(money){var total=1000;total-=money;console.log(`花了${money},还剩${total}`);
}
pay(100);
pay(100);

发现局部变量是不可重用的,导致结果错误:
在这里插入图片描述

一、闭包函数

解决方案:使用闭包函数

1.什么是闭包函数?

外层函数的作用域对象,在外层函数调用后,依然被内层函数引用着,无法释放,形成了闭包。

满足上述两个条件,如果在外部函数调用这个内部函数,就成为闭包函数。

2.步骤

求函数依赖集的闭包。①用外层函数包裹要保护的变量和使用变量的内层函数
②在外层函数内部,返回内层函数对象。
③调用外层函数,用变量接住返回的内层函数对象。

3. 何时使用

希望给一个函数保护一个可反复使用的专属变量,又防止这个变量被外部篡改

4.代码结构

function f(x) {       //外部函数var a = x;    		//外部函数的局部变量//↓返回的闭包体结构var b = function() {    //内部函数(定义一个闭包)return a;    //访问外部函数中的局部变量};a++;return b;    //返回 内部函数整个结构!
}
var c = f(5);   //调用外部函数,返回内部函数
// c返回的是一个函数//c是一个函数,用()才会调用 
alert(c());     //调用内部函数,返回值6

二、示例图解

如果要直接看结论,可跳过此处图解,直接看“三”

针对引入的问题,给出正确的解决代码:

//1. 用外层函数包裹要保护的变量和使用变量的内层函数
function mother(){var total=1000;//2. 在外层函数内部,返回内层函数对象。return function(money){//从总价中减去本次花的钱total-=money;console.log(`花了${money},还剩${total}`);}
}
//3. 调用外层函数,用变量接住返回的内层函数对象。
var pay=mother();
// pay返回的是一个函数
//pay:function(money){//total-=money;//console.log(`花了${money},还剩${total}`);
//}//pay是一个函数,用()才会调用 
pay(100);//剩900
//别人代码中的,使用闭包后不会影响
total=0;
pay(100);//剩800

①函数定义时
window对象中有全局函数mother和全局变量pay,mother通过函数的地址0x1234引用函数,函数自有一个作用域链,一个为空,一个为window;pay暂时还未接收值,故为undefined。

0x1234

求闭包的算法?②函数调用时
调用外部函数mother时,临时创建函数作用域对象,地址为0x9091,地址保存到mother函数的作用域链中。
在这里插入图片描述

接下来,会临时创建一个内层函数对象,并返回到外部来,地址为0x2345
function的底层就是new Function,new Function会在外部创建一个函数

然后根据pay = mother();把新的地址赋给pay
在这里插入图片描述
③mother函数调用后
当执行完pay = mother();,清空mother作用域链的第一个格子的地址,这时mother不再和mother的函数作用域对象关联。
由于内层函数仍引用mother函数作用域对象,故不能释放mother的函数作用域对象,此时mother作用域对象和mother函数无关系
在这里插入图片描述
执行pay(100),调用内层函数
临时创建一个pay的函数作用域,地址为0x2468,局部变量为money
在这里插入图片描述
⑤执行内层函数的total-=money
就近原则,先找第一个格子里,有money = 100,语句为total-=100;
在这里插入图片描述
然后找到第二个格子中有total,执行语句total-=100;,故total为900
在这里插入图片描述
⑥第一个pay(100)执行完毕后,清空作用域链的最近一个格子
在这里插入图片描述
⑦执行total=0,total全局变量,不能在函数内寻找,但在window中没有找到total=0,自动在全局创建
在这里插入图片描述
⑧执行pay(100,重复④⑤⑥⑦
在这里插入图片描述
调用完pay(100)后:
在这里插入图片描述

三、简化记忆

(1)外层函数:妈妈
(2)内层函数:孩子
(3)外层函数的局部变量:红包

  • 当调用外层函数(妈妈)时,生出(return)内层函数(孩子)
  • 孩子(内层函数)拿着(引用)红包(外层函数的作用域对象),独立门户,形成了闭包。
    在这里插入图片描述

四、缺点

闭包产生的内层函数比普通函数多占用一块内存空间——外层函数的作用域对象

js for循环闭包,解决:
如果一个闭包结构不再使用,记得手动释放

只要将引用内层函数的变量赋值为null->内层函数被释放->外层函数的作用域对象也就释放
例:pay = null

五、拓展题目

1.多次生孩子情况

一个妈妈生两次孩子,两个孩子分别得到属于自己的红包,互不干扰

function mother(){var total=1000;return function(money){total-=money;console.log(`花了${money},还剩${total}`);}
}
var pay=mother();//妈妈生第一个小孩,临时为小孩包一个红包1,小孩1拿着红包1独立门户
pay(100);//剩900
pay(100);//剩800var pay2 = mother();//妈妈生第二个小孩,临时为小孩包一个红包2,小孩2拿着红包2独立门户
pay(100);//剩900

在这里插入图片描述

2.双胞胎情况

function fun() {//妈妈var n = 999;  //红包:函数作用域对象nAdd = function() { //另一个孩子n++;};return function() { //一个孩子console.log(n);}
}
var getN = fun();//妈妈生小孩,包一个红包
getN();//999
nAdd();
getN();//1000

解:
在函数fun中,有返回nAdd和return的两个匿名函数,这两个都是fun的孩子。但主程序中只生一次孩子(调用一次fun函数),所以这两个函数应共用一个红包(外层函数的函数作用域)
在这里插入图片描述

数据库闭包的例题,所以两个孩子应该与一个红包独立门户(形成闭包),在闭包中的内容加上nAdd = function(){n++};
在这里插入图片描述=>在这里插入图片描述
第一次打印结果为999,执行nAdd()后,两个孩子共用的n++,故第二次getN打印结果为1000

六、技巧

画简图,判断闭包,找两样东西:
(1)外层函数与内层函数之间都有哪些受保护的变量.
(2)外层函数共向外抛出了几个内层函数对象!
三种方式:

  • return function() {……}
  • 直接给全局变量赋值的方式,向外抛出一个对象
  • return一个对象或数组,在对象和数组中包含多个函数定义

结论: 一次外层函数调用时,抛出的多个内层函数对象,共用这次生成的一个变量。
其中一个函数修改了变量,另一个函数使用受保护的变量时,也受影响。.

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/48827.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息