喵喵教主教 2024-07-14 17:42 采纳率: 0%
浏览 2

关于#typescript#的问题:在解除对闭包instance的引用后,再次创建闭包应该为sven2,可是实际上还是sven1,并没有对闭包变量进行回收

问题描述

个人理解:如果引用闭包变量的对象都解除引用,那么闭包会被垃圾回收。查阅的解除引用的方法是将其设置成null,但是实际使用确并未解除。

复现代码

npx ts-node index.ts
// index.ts
const CreateDiv = (() => {
    let instance: CreateDiv;
    class CreateDiv {
        html: string = "";
        constructor(html: string) {
            if (instance) {
                return instance;
            }
            this.html = html;
            return instance = this;
        }
        getName() {
            console.log(this.html);
        }
    }
    return CreateDiv;
})();

let a: any = new CreateDiv("sven1");
let b: any = new CreateDiv("sven2");

console.log(a === b);
a.getName();    // sven1
b.getName();    // sven1

a = null;
b = null;

setTimeout(() => {
    b = new CreateDiv("sven2");
    a = new CreateDiv("sven1");
    a.getName();    // sven1
    b.getName();    // sven1
}, 1000);

export {};

预期结果

在解除对闭包instance的引用后,再次创建闭包应该为sven2,可是实际上还是sven1,并没有对闭包变量进行回收

> sven1
> sven1
> sven2
> sven2

实际结果

未被回收

> sven1
> sven1
> sven1
> sven1

系统环境

$ uname -a
> Linux codespaces-b61014 6.5.0-1022-azure #23~22.04.1-Ubuntu SMP Thu May  9 17:59:24 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
$ node -v
> v20.15.1
$ npm -v
> 10.7.0
$ npm list
> js_design_models@ /workspaces/js_design_models
  ├── ts-node@10.9.2
  └── typescript@5.5.3
  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-07-14 17:42
    关注

    引自免费微信小程序:皆我百晓生

    你的问题与JavaScript中的闭包和垃圾回收机制有关。在JavaScript中,垃圾回收器不会自动回收闭包中的变量,除非没有任何地方再引用这些变量。在你的代码中,闭包CreateDiv中有一个私有变量instance,这个变量即使在外层引用被设为null后也不会被垃圾回收,因为它仍然被闭包内部引用。这就导致当你试图创建新的CreateDiv实例时,它仍然返回之前的实例(sven1)。这是因为instance变量并没有被解除引用,它仍然存在于内存中。即使你把外部引用设为null,由于闭包内部的引用,它也不会被垃圾回收。这就是你遇到的问题。

    要解决这个问题,你需要手动清除闭包内部的引用。你可以在CreateDiv的构造函数中添加一个清理函数来清除instance变量的引用。当你不再需要某个实例时,可以调用这个函数来清除内部引用。以下是一个修改后的代码示例:

    const CreateDiv = (() => {
        let instance: CreateDiv | null = null; // 使用null作为初始值
        class CreateDiv {
            html: string;
            constructor(html: string) {
                if (instance) {
                    this.dispose(); // 如果已有实例存在,先调用清理函数释放资源
                }
                this.html = html;
                instance = this; // 更新实例引用为当前对象
            }
            getName() {
                console.log(this.html);
            }
            dispose() { // 添加清理函数,移除闭包内部引用
                instance = null; // 清除外部引用(这样这个实例在不再需要时可以触发垃圾回收)
            }
        }
        return CreateDiv;
    })();
    

    然后在代码中当你不再需要一个实例时调用dispose()函数:

    // ...其他代码...
    a?.dispose(); // 在a可能为null之前先尝试调用dispose方法清除引用
    b?.dispose(); // 对b做同样处理
    a = null; // 之后再将a设为null会更安全地执行操作而不会抛出异常,因为此时我们知道已经清除了内部引用。同理对b也做同样的操作。...其他代码...setTimeout(() => {...})...export {};`这样修改后当你再次创建新的CreateDiv实例时就会得到预期的结果了。垃圾回收器将在没有任何外部引用时正确地清理这个闭包和内部的实例变量。但是要注意手动调用清理函数非常重要因为你需要通过清理函数显式地将内部的闭包和外部变量的连接断开才能使它们得到回收在你不使用的时候如果你想尝试以更加优雅的方式管理资源你也可以考虑使用其他技术如弱引用或者依赖注入等但这需要更复杂的代码设计如果你想要的话我可以提供更多关于这方面的信息
    
    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 7月14日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?