最终,JS将拥有内置的代理功能,该功能将以低级别访问背景中发生的各种事情,并且前端开发人员(除非通过代理,类似于PHP中的魔术方法)不会暴露它。
在那个时候,在对象上编写一个析构方法来递减计数器可能会非常简单,只要对销毁/垃圾回收的支持在所有平台上都被100%保证。
目前唯一可靠的方法可能是创建一个封闭注册表来跟踪所有已创建的实例,然后手动销毁它们(否则,它们将永远不会被垃圾回收)。
var Obj = (function () {
var stack = [],
removeFromStack = function (obj) {
stack.forEach(function (o, i, arr) {
if (obj === o) { arr.splice(i, 1); }
makeObj.count -= 1;
});
};
function makeObj (name) {
this.sayName = function () { console.log("My name is " + this.name); }
this.name = name;
this.explode = function () { removeFromStack(this); };
stack.push(this);
makeObj.count += 1;
}
makeObj.checkInstances = function () { return stack.length; };
makeObj.count = 0;
return makeObj;
}());
var a = new Obj("Dave"),
b = new Obj("Bob"),
c = new Obj("Doug");
Obj.count;
a.explode();
Obj.count;
a = null;
这个模式能够实现你想要的功能吗?
只要:
- 你不把
a
变成其他东西
- 你不覆盖它的
explode
方法
- 你不以任何方式干扰
Obj
- 你不期望任何
prototype
方法可以访问任何内部变量
...那么是的,这个方法将很好地使计数器正常工作。
你甚至可以编写一个通用方法叫做 recycle
,它调用任何你传递给它的对象的 explode
方法(只要它的构造函数或工厂支持这样做)。
function recycle (obj) {
var key;
obj.explode();
for (key in obj) { if (obj.hasOwnProperty(key)) { delete obj[key]; } }
if (obj.__proto__) { obj.__proto__ = null; }
}
注意 - 这实际上并不会摆脱对象。
你只是从闭包中移除了它,并移除了它曾经拥有的所有方法/属性。
所以现在它是个空壳,你可以重新使用它,在回收其部分后明确设置为 null,或者让它被收集起来并忘记它,知道你删除了必要的引用。
这有用吗?
可能不是。
我真正认为唯一有用的时候是在一个游戏中,你的角色可能只能同时发射 3 发子弹,而且直到屏幕上的第一颗子弹击中某人或离开边缘后才能发射第四颗(就像以前的 Contra 游戏)。
你还可以将一个 "消失" 的子弹从堆栈中移除,并通过重置其轨迹、重置适当的标志,并将其推回到堆栈中以供任何玩家/敌人重用。
但再说一次,直到代理允许我们定义在低级别受到尊重的 "魔术" 构造函数/析构函数方法,这仅在你要微观管理自己所有对象的创建和销毁时才有用(真的不是一个好主意)。
MyObj.prototype
或MyObj
中,或通过闭包添加私有变量(这些都无法解决 Lee Taylor 提到的问题)。 - nnnnnn