当前位置: 首页 > 知识库问答 >
问题:

javascript - JS 对于闭包的理解不够彻底?

洪弘壮
2024-03-01

JS代码

function fn() {  var num = 3;  return function() {      var n = 0;      n++;      num++;      console.log('n=' + n);      console.log('num=' + num);  }}var fn1 = fn();fn1(); // 1 4console.log("------");fn1(); // 1 5

变量 num 在函数执行完毕后没有被销毁,当我第二次调用 fun1 的时候输出 num=5,而变量 n 每次执行时都会创建一个新的,导致两次调用输出都是 1,这是为什么?同样都是函数内部的变量
变量 num 在执行过程中是如何被保留下来的?

共有5个答案

强承望
2024-03-01

变量 num 和变量 n 之所以表现不同,关键在于他们所处的作用域和闭包的行为。

变量 num: 它定义在函数 fn 的作用域内。当你调用 fn() 时,它创建了一个闭包,这个闭包包含了对 num 的引用。根据闭包的工作原理,即使 fn 的执行上下文已经结束,num 依然被闭包内的匿名函数引用,因此它不会被垃圾回收机制回收。这就是为什么 num 的值在闭包函数(fn1)的连续调用之间被保留的原因。

变量 n: 它定义在闭包函数(匿名函数)的作用域内。每次调用 fn1 时,匿名函数都会创建一个新的执行上下文,其中包括一个新的 n 变量。因为 n 没有被外部的任何函数或闭包引用,它的生命周期仅限于闭包函数的单次调用。所以每次调用 fn1 的时候,n 都会重置为 0,然后增加到 1,然后在函数执行完毕后被销毁。

总结来说,num 能够在函数调用之间保留下来是因为它是通过闭包保持在内存中的,而 n 在每次调用结束后都会消失,因为它仅存在于函数调用的局部作用域中。

以上来自 GPT4
鲜于俊侠
2024-03-01

��看你21年就开始写js代码了,24年在这钻牛角尖是吧?
fn函数根据你写的逻辑
你把fn函数想象成一个妈妈,执行它可以生很多小孩,
生小孩的时候这个小孩身高是3(var num = 3)

  1. 这个小孩每一年(调用一次)都会从0(var n = 0)开始存钱,每次存1块钱(n++)
  2. 这个小孩从3开始长高,每一年(调用一次)这个小孩长高1(num++)
谭学名
2024-03-01

可以看看MDN权威的文档,我觉得讲的很清楚:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
定义上来说闭包是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。闭包函数就是定义在一个函数里面的函数,这个函数(内部函数)可以访问到外部函数的作用域。回到题目中:

function fn() {  var num = 3;  return function() { //这个匿名函数就是闭包函数,它可以访问到外部函数fn()的作用域      var n = 0;      n++;      num++;      console.log('n=' + n);      console.log('num=' + num);  }}

一个函数执行完后,垃圾回收器会回收已经没有被引用的对象实例

我们注意到

var fn1 = fn();

这个fn1是执行外部函数fn()时创建的匿名函数(内部函数)实例的引用,那么当外部函数fn()执行完后,这个引用的匿名函数(内部函数)对象实例并不会被回收,所以它的状态就一直被保持了下来,下次再调用fn()的时候引用指向的还是同一个匿名函数(内部函数)对象实例,对于外部函数里定义的

var num = 3;

被这个匿名函数引用了,所以同样也不会被回收,下次再执行fn()时是不会重新创建num这个变量的,还是对同一个num进行操作
对于内部的匿名函数里定义的

var n = 0;

在内部的匿名函数执行完后就被回收了,因为没有人对它持有引用,所以下次再执行fn()时会重新创建一个新的n并且初始化为0
所以闭包是有内存泄露的风险的,如果一个闭包函数引用外部函数的对象引用,而它自己本身一直被引用没有释放,那么外部函数的对象实例就不会被回收。

吴正祥
2024-03-01
当一个函数可以通过某种方式访问其它函数内部变量时,闭包就形成了

你每次执行fn1,里面的var n = 0,都把n初始化为0了。

fn其实也遵循这个规律,函数都这样。

但是,你的fn在复赋值给fn1之后,就没有再执行了。所以里面的num没有被重新赋值,又由于闭包的作用让它不会被销毁(语言引擎特性),使得你在每次调用fn1都可以访问到它累积起来的值。

回到开头的话,你的fun1就有能力访问fn内部的num。也就形成了闭包。闭包的特性就使得num不会被销毁(因为外面有函数可能会访问num,不销毁才合理)。

function fn() {  var num = 3;  // 这里加一个console.log  console.log('outer num', num);  return function() {      var n = 0;      n++;      num++;      console.log('n=' + n);      console.log('num=' + num);  }}// 连续调用两次看看,num的表现和n是一样的fn()fn()

附一下阮一峰的闭包文章(阮一峰,我的hero!)

学习Javascript闭包(Closure)

钱均
2024-03-01

在 JavaScript 中,函数内部定义的变量具有闭包。闭包是一种函数,它能够记住并访问其词法作用域,即使该函数在其词法作用域之外执行。这意味着,当函数返回另一个函数时,外部函数的作用域被封装在内部函数中,形成一个闭包。

在你的例子中,fn 函数返回了一个匿名函数,这个匿名函数创建了自己的作用域并引用了 num 变量。即使 fn 函数已经执行完毕,这个匿名函数仍然保持了对 num 变量的引用,因此 num 变量不会被垃圾回收。

每次你调用 fn1() 时,实际上是调用了匿名函数。这个匿名函数创建了自己的作用域,并且有自己的 n 变量。每次调用时,n 都会被初始化为 0,然后自增 1,同时 num 也自增 1。由于 n 是在匿名函数的作用域内定义的,所以每次调用时都会创建一个新的 n 变量。而 num 变量由于闭包的作用被保留了下来。

所以,第一次调用 fn1() 时,输出的是 n=1num=4。第二次调用时,由于 num 已经被闭包保留下来并自增了 1,所以输出的是 n=1num=5

 类似资料:
  • 本文向大家介绍javascript闭包的理解,包括了javascript闭包的理解的使用技巧和注意事项,需要的朋友参考一下 1、首先我们要知道变量作用域链 变量的作用域分两种:全局变量和局部变量。没有定义到任何函数中的变量为全局变量,在函数中定义的变量为局部变量,注意在函数内部定义变量时一定要使用var关键字,不带var关键字的变量为全局变量。 javascript中每一段代码都有与之关联的作用域

  • 本文向大家介绍彻底理解js面向对象之继承,包括了彻底理解js面向对象之继承的使用技巧和注意事项,需要的朋友参考一下 说道这个继承,了解object-oriented的朋友都知道,大多oo语言都有两种,一种是接口继承(只继承方法签名);一种是实现继承(继承实际的方法) 奈何js中没有签名,因而只有实现继承,而且靠的是原型链实现的。下面正式的说一说js中继承那点事儿 1、原型链 原型链:实现继承的主要

  • 本文向大家介绍详解js闭包,包括了详解js闭包的使用技巧和注意事项,需要的朋友参考一下 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收 闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一

  • 本文向大家介绍谈谈你对闭包的理解?相关面试题,主要包含被问及谈谈你对闭包的理解?时的应答技巧和注意事项,需要的朋友参考一下 说明: bar在foo函数的代码块中定义。我们称bar是foo的内部函数。 在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。 简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。 闭包的意义与应用  

  • 本文向大家介绍Javascript的闭包详解,包括了Javascript的闭包详解的使用技巧和注意事项,需要的朋友参考一下 前言:还是一篇入门文章。Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将以例子入手来介绍Javascript闭包的语言特性,并结合一点 ECMAScript语言规范来使读

  • 本文向大家介绍JavaScript闭包详解,包括了JavaScript闭包详解的使用技巧和注意事项,需要的朋友参考一下 在上一篇文章我们对预解释作了概述,在写这篇博文前打算写几个经典案例,考虑到那些案例综合性比较强,也就循序渐进的有了这篇博文,这样对于学习和深入JavaScript也更加容易入手。 序 一同事去面试,面试官问了一道题:你写一个闭包我看下?于是同事火速写出如下代码: 然后面试官摇摇头