【发布时间】: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 中,至少我知道没有办法模仿这种行为。在过去 let 和 const 不是语言的一部分时,这将不那么有用,甚至是危险的,因为人们永远不会真正知道 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