【问题标题】:Is there any way for a Javascript object to know when it is going out of scope?Javascript对象有什么方法可以知道它何时超出范围?
【发布时间】:2021-01-25 06:30:19
【问题描述】:

在诸如 C++ 之类的语言中,能够检测对象何时超出范围在广泛的用例(例如,智能指针、文件访问、互斥体、分析)中非常有用。而且我在这里不是在谈论内存管理与垃圾收集,因为这是一个不同的话题。

考虑一个像这样的简单 C++ 示例

class Profiler {
  uint64 m_startTime;

  Profiler::Profiler() : 
    m_startTime(someTimeFunction()) {
  }

  Profiler::~Profiler() {
    const uint64 diff = someTimeFunction() - m_time;
    printf("%llu ms have passed\n", diff);
  }
}

我们可以这样做

{
    Profiler p; // creation of Profiler object on the stack

    // Do some calculations

} // <- p goes out of scope and you will get the output message reporting the number of ms that have been passed

这个简洁的例子展示了作用域的威力。作为一名程序员,我不需要担心手动调用方法;规则很简单:一旦对象超出范围,就会调用析构函数,我可以使用它。

然而,在 Javascript 中,至少我知道没有办法模仿这种行为。在过去 letconst 不是语言的一部分时,这将不那么有用,甚至是危险的,因为人们永远不会真正知道 var 何时超出范围。

但是当添加块作用域时,我希望程序员能够对对象何时超出作用域进行一些控制。例如,当超出范围时调用的特殊方法(如contructor())。但是AFAIK这还没有完成。没有添加这个有什么原因吗?

现在我们必须手动调用一个函数,这违背了为所述用例设置块范围的整个目的。

这将是上述 C++ 代码的 Javascript 等价物:

class Profiler {
  constructor() {
    this.m_time = new Date().getTime(); 
  }
  
  report() {
    const diff = new Date().getTime() - this.m_time;
    console.log(`${diff} ms have passed`);
  }
}

用例是这样的

{
    const p = new Profiler;

    // Do some calculations
    p.report();
} 

这显然不太理想。因为如果我不小心将 p.report(); 放在块的末尾,则报告不正确。

如果还有办法做到这一点,请告诉我。

[编辑]

我想出的最接近的东西是这个“黑客”。我使用了async,但如果块中的所有代码都是同步的,显然可以省略。

// My profiler class
class Profiler {
    constructor() {
        this.m_time = new Date().getTime();
    }

    // unscope() is called when the instance 'goes out of scope'
    unscope() {
        const diff = new Date().getTime() - this.m_time;
        console.log(`took ${diff} ms`);
    }
};

async function Scope(p_instance, p_func) {
    await p_func();
    p_instance.unscope();
};

await Scope(new Profiler(), async () =>
{
    console.log("start scope")
    await sleep(100);
    await Scope(new Profiler(), async () =>
    {
        await sleep(400);
    });

    await sleep(3000);
    console.log("end scope")
});
console.log("after scope")

导致

start scope
took 401 ms
end scope
took 3504 ms
after scope

这是我所期望的。但是又是

await Scope(new Profiler(), async () =>
{
});

远不如简单直观

{
   const p = new Profiler();
}

但至少我能够做我想做的事。如果其他人有更好的解决方案,请告诉我。

【问题讨论】:

  • 这能回答你的问题吗? ECMAScript 6 class destructor
  • 不完全是,因为它特别提到了一个析构函数,这也意味着该对象被删除(垃圾收集或手动)。如果他们能满足于当对象超出范围时调用的特定方法(例如,unscope),我会很高兴。这将把整个析构函数的讨论留到另一天:)

标签: javascript destructor scoping


【解决方案1】:

析构函数是实现它的一种方法,但遗憾的是 Javascript 不支持它。超出范围后您自动获取配置文件报告的原因可能是因为它的析构函数是在 C++ 中调用的。到目前为止,Javascript 中没有析构函数。如您所展示的那样手动执行将是实现 C++ 所需行为的最简单方法。

不同的语言带来不同的语法和功能来做事。有时你需要适应这些差异。在您的情况下,C++ 代码不太容易出错,但我认为没有一种简单的方法可以实现所需的行为

【讨论】:

    猜你喜欢
    • 2011-12-30
    • 2012-04-22
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 2015-01-19
    相关资源
    最近更新 更多