相当于JavaScript'对象模型中的析构函数
Equivalent of destructors in JavaScript's object model
由于我过去已经处理过JavaScript的古怪的"对象模型",所以我假设没有析构函数这样的东西。我的搜索都没有成功,所以你们是我最后的希望了。如何在实例销毁时执行程序?
MDN是一个很好的JS资源。不,没有什么比在对象停止时调用函数更好的了。
FinalizationRegistry可能就是您需要的。它不是析构函数,但是一旦对象被垃圾收集,它就执行一个函数。在任何情况下,这是我希望我发现当我第一次来到这里:)
除了已经提到的为非确定性终结提供支持的FinalizationRegistry
之外,还有一项提案(截至2023年3月撰写本文时)正在向该语言添加一个确定性的、基于作用域的清理构造:显式资源管理。它可能在2023年或2024年达到标准。
语法已经经历了多次迭代,但是考虑到它已经经过了阶段3的审查,现在不太可能有太大的变化。下面是一个包装URL.createObjectURL
的演示:
class BlobURL {
#url = null;
constructor(blob) {
this.#url = URL.createObjectURL(blob);
}
toString() {
if (this.#url == null)
throw new TypeError("URL was already revoked");
return this.#url;
}
valueOf() {
return this.#url;
}
[Symbol.dispose]() {
URL.revokeObjectURL(this.#url);
this.#url = null;
}
}
const doIFeelLucky = (url) => {
// imagine some process here that
// uses the URL, but may throw
if (6 * Math.random() < 1)
throw new Error("seems I don't");
};
const processBlob = (blob) => {
using url = new BlobURL(blob);
doIFeelLucky(url);
// `url` is revoked when the function returns or throws
};
所有权转移有点笨拙,因为它需要创建一个DisposableStack
来管理它:
const processBlobAndReturnItsURL = (blob) => {
using stack = new DisposableStack();
const url = stack.use(new BlobURL(blob));
doIFeelLucky(url); // if this throws, `url` will be revoked
stack.move(); // release ownership
return url; // `url` will be returned without being revoked
}
其他缺点:不支持解构(尽管在提案进行时有许多建议允许它),并且构造的表达能力不足以像Python上下文管理器那样执行异常捕获(尽管这是否真的有意义是有争议的)。尽管如此,它还是比我们现在使用的finally
稍微好一些。
最近,这个链接更多地用于回答这个问题。最重要的部分:
截至2012年,所有现代浏览器都提供了标记和清除功能垃圾收集器。
…
循环不再是问题
在上面的第一个例子中,函数调用返回后,两个对象不再被任何可访问的资源引用从全局对象。因此,他们将被发现是遥不可及的由垃圾回收器回收它们分配的内存。
限制:手动释放内存
有些时候手动决定什么时候会很方便以及释放了哪些记忆。为了释放一个人的记忆对象,则需要显式地使其不可访问。
所以就循环引用而言,de[con]构造函数并不是真正需要的。
我想到了一个很酷的技巧,如果你有循环引用,你想要轻松地手动控制对解构…
class Container {
constructor() {
this.thisRef = [ this ];
this.containee = new Containee({ containerRef: this.thisRef });
}
//Note: deconstructor is not an actual JS thing/keyword.
deconstructor() {
//Have to delete `this.thisRef[0]` and not `this.thisRef`, in
//order to ensure Containee's reference to Container is removed.
delete this.thisRef[0];
}
doSomething() {
}
}
class Containee {
constructor({ containerRef }) {
//Assumption here is, if the Container is destroyed, so will the Containee be
//destroyed. No need to delete containerRef, no need for a
//deconstructor function!
this.containerRef = containerRef;
}
someFunc() {
this.containerRef[0].doSomething();
}
}
let c = new Container();
...
//No cyclic references!
c.deconstructor();
所以在这里,Containee类不是存储对Container实例的直接引用,而是存储对一个大小为1的数组的引用,该数组包含Container引用,然后容器实例本身可以从中删除自己。包含引用的数组由Container管理。
但是,这不是真正需要的,因为所有现代浏览器中的垃圾收集都是标记-清除,并且可以处理循环引用。
- 如何使用Javascript客户端对象模型检索Sharepoint 2010列表项权限
- Angular,函数在(模型)工厂中返回值
- 在javascript中调用函数/对象引用时,可容纳任何数据类型
- 访问函数对象的上下文属性|如何
- 将ECMAScript 6析构函数赋值(ES2015)重构为旧版本的javascript
- 为什么可以'我们在函数体中为函数对象添加属性,就像在javascript中为对象文字添加属性一样
- 在ES6中将数组析构函数参数的语法
- 使用Javascript对象模型
- 如何将函数对象从javascript传递到Polymer元素
- 为什么函数对象的实例没有继承函数原型属性
- 使用扩展运算符和析构函数运算符修改不可变对象的最短方法是什么
- 避免在析构函数参数中重复
- CoffeeScript-如何将长的析构函数赋值分解为多行
- ECMAScript 2015,可迭代的析构函数表达式
- js -是否有析构函数
- 在aurelia的视图模型类中有析构函数吗?
- 如何在Sharepoint 2013客户端对象模型中使用javascript getPeerUrl()函数
- 如何在ES6中引用未命名的析构函数参数
- 在对象析构函数中使用默认值,同时保留任何非默认值
- 相当于JavaScript'对象模型中的析构函数