最终,JS 将拥有内置的代理能力,它将对后台发生的各种事情进行低级访问,永远不会暴露给前端开发人员(通过代理除外——think magic -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;
}());
// usage:
var a = new Obj("Dave"),
b = new Obj("Bob"),
c = new Obj("Doug");
Obj.count; // 3
// "Dave? Dave's not here, man..."
a.explode();
Obj.count; // 2
a = null; // not 100% necessary, if you're never going to call 'a', ever again
// but you MUST call explode if you ever want it to leave the page's memory
// the horrors of memory-management, all over again
这个模式会做你想做的事吗?只要:
- 你不会
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 发子弹,并且在屏幕上的第 1 发子弹击中某人或熄灭之前,他不能射击第 4 发子弹边缘(这就是,比如说,Contra 在当时是如何工作的)。
您也可以将“消失”的子弹从堆栈中移出,并通过重置其轨迹、重置适当的标志并将其推回堆栈来为任何玩家/敌人重复使用该子弹。
但是再一次,直到代理允许我们定义“神奇”的构造函数/析构函数方法,这些方法在低级别得到尊重,这只有在你要微观管理你自己的所有对象的创建和销毁时才有用(真的不是一个好主意)。