javascript 如何计算对象的实例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12378909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I count the instances of an object?
提问by Johnydep
If i have a Javascript object defined as:
如果我有一个 Javascript 对象定义为:
function MyObj(){};
MyObj.prototype.showAlert = function(){
alert("This is an alert");
return;
};
Now a user can call it as:
现在用户可以将其称为:
var a = new MyObj();
a.showAlert();
So far so good, and one can also in the same code run another instance of this:
到目前为止一切顺利,您还可以在同一代码中运行另一个实例:
var b = new MyObj();
b.showAlert();
Now I want to know, how can I hold the number of instances MyObj? is there some built-in function?
现在我想知道,我怎样才能保存MyObj的实例数?有什么内置函数吗?
One way i have in my mind is to increment a global variable when MyObj is initialized and that will be the only way to keep track of this counter, but is there anything better than this idea?
我想到的一种方法是在初始化 MyObj 时增加一个全局变量,这将是跟踪这个计数器的唯一方法,但有什么比这个想法更好的方法吗?
EDIT:
编辑:
Have a look at this as suggestion here:
看看这个作为这里的建议:
I mean how can I make it get back to 2 instead of 3
我的意思是我怎样才能让它回到 2 而不是 3
回答by maerics
There is nothing built-in; however, you could have your constructor function keep a count of how many times it has been called. Unfortunately, the JavaScript language provides no way to tell when an object has gone out of scope or has been garbage collected, so your counter will only go up, never down.
没有任何内置的东西;但是,您可以让构造函数记录它被调用的次数。不幸的是,JavaScript 语言无法判断对象何时超出范围或已被垃圾回收,因此您的计数器只会上升,而不会下降。
For example:
例如:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
new MyObj();
new MyObj();
MyObj.numInstances; // => 2
Of course, if you want to prevent tampering of the count then you should hide the counter via a closure and provide an accessor function to read it.
当然,如果你想防止篡改计数,那么你应该通过闭包隐藏计数器并提供一个访问器函数来读取它。
[Edit]
[编辑]
Per your updated question - there is no way to keep track of when instances are no longer used or "deleted" (for example by assigning null to a variable) because JavaScript provides no finalizer methodsfor objects.
根据您更新的问题 - 无法跟踪实例何时不再使用或“删除”(例如通过将 null 分配给变量),因为 JavaScript 没有为对象提供终结器方法。
The best you could do is create a "dispose" method which objects will call when they are no longer active (e.g. by a reference countingscheme) but this requires cooperation of the programmer - the language provides no assistance:
您能做的最好的事情是创建一个“处置”方法,当对象不再活动时(例如通过引用计数方案),该方法将调用该方法,但这需要程序员的合作 - 该语言不提供任何帮助:
function MyObj() {
MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
MyObj.prototype.dispose = function() {
return MyObj.numInstances -= 1;
};
MyObj.numInstances; // => 0
var a = new MyObj();
MyObj.numInstances; // => 1
var b = new MyObj();
MyObj.numInstances; // => 2
a.dispose(); // 1 OK: lower the count.
a = null;
MyObj.numInstances; // => 1
b = null; // ERR: didn't call "dispose"!
MyObj.numInstances; // => 1
回答by Aadit M Shah
Create a static property on the MyObj
constructor called say count
and increment it within the constructor itself.
在MyObj
构造函数上创建一个名为 say的静态属性,count
并在构造函数本身内增加它。
function MyObj() {
MyObj.count++;
}
MyObj.count = 0;
var a = new MyObj;
var b = new MyObj;
alert(MyObj.count);
This is the way you would normally do it in say Java (using a static property).
这是您通常在 Java 中执行的方式(使用静态属性)。
回答by Ignacio Martínez
var User = (function() {
var id = 0;
return function User(name) {
this.name = name;
this.id = ++id;
}
})();
User.prototype.getName = function() {
return this.name;
}
var a = new User('Ignacio');
var b = new User('foo bar');
a
User {name: "Ignacio", id: 1}
b
User {name: "foo bar", id: 2}
回答by Ani Naslyan
Keeping a global count variable and incrementing every time is an option. Another option is to call counter
method after each instance creation by hand (the worst thing I could imagine). But there is another better solution.
Every time we create an instance, the constructor function is being called. The problem is the constructor function is being created for each instance, but we can have a count
property inside __proto__
which can be the same for each instance.
保持全局计数变量并每次递增是一种选择。另一种选择是counter
在每个实例创建后手动调用方法(我能想象的最糟糕的事情)。但是还有另一个更好的解决方案。
每次我们创建一个实例时,都会调用构造函数。问题是正在为每个实例创建构造函数,但是我们可以count
在__proto__
其中有一个属性,每个实例都可以使用相同的属性。
function MyObj(){
MyObj.prototype.addCount();
};
MyObj.prototype.count = 0;
MyObj.prototype.addCount = function() {
this.count++;
};
var a = new MyObj();
var b = new MyObj();
回答by Roko C. Buljan
Using ES6 ClassesMDNsyntax - we can define a static
method:
使用ES6 Classes MDN语法 - 我们可以定义一个static
方法:
The
static
keyword defines a static method for a class. Static methods are called without instantiating their class and cannot be called through a class instance. Static methods are often used to create utility functions for an application.
的
static
关键字定义为一个静态方法类。静态方法在没有实例化它们的类的情况下被调用,并且不能通过类实例调用。静态方法通常用于为应用程序创建实用程序函数。
class Item {
static currentId = 0; // (PS: You can replace globally `currentId` with `id`)
_id = ++Item.currentId; // Set Instance's this._id to incremented class's ID
// The above line is the same as doing:
// constructor () { this._id = ++Item.currentId; }
get id() {
return this._id; // Getter for the instance's this._id
}
}
const A = new Item(); // Create instance (Item.currentId is now 1)
const B = new Item(); // Create instance (Item.currentId is now 2)
const C = new Item(); // Create instance (Item.currentId is now 3)
console.log(A.id, B.id, C.id); // 1 2 3
console.log(`Currently at: ${ Item.currentId }`); // Currently at: 3
PS: if you don't want to log-expose the internal currentId
property, make it private:
PS:如果您不想记录-expose 内部currentId
属性,请将其设为私有:
static #currentId = 0;
_id = ++Item.#currentId;
Here's an example with constructor
and without the getter:
这是一个有constructor
和没有 getter的例子:
class Item {
static id = 0;
constructor () {
this.id = ++Item.id;
}
getID() {
console.log(this.id);
}
}
const A = new Item(); // Create instance (Item.id is now 1)
const B = new Item(); // Create instance (Item.id is now 2)
const C = new Item(); // Create instance (Item.id is now 3)
A.getID(); B.getID(); C.getID(); // 1; 2; 3
console.log(`Currently at: ${ Item.id }`); // Currently at: 3
回答by volod
what about such method?
这样的方法怎么样?
var Greeter = (function ()
{
var numInstances;
function Greeter(message)
{
numInstances = (numInstances || 0) + 1;
this.greeting = message;
}
Greeter.prototype.greet = function ()
{
return "Hello, " + this.greeting;
};
Greeter.prototype.getCounter = function ()
{
return numInstances;
};
return Greeter;
})();
var greeter = new Greeter("world");
greeter.greet();
greeter.getCounter();
var newgreeter = new Greeter("new world");
newgreeter.greet();
newgreeter.getCounter();
greeter.getCounter();
回答by Norguard
Eventually, JS is going to have built-in proxy capability, which will have low-level access to all kinds of things which happen in the background, which will never be exposed to front-end developers (except through the proxy -- think magic-methods in languages like PHP).
最终,JS 将具有内置的代理能力,它可以低级访问后台发生的各种事情,永远不会暴露给前端开发人员(除非通过代理——想想魔法-PHP 等语言中的方法)。
At that time, writing a destructor method on your object, which decrements the counter might be entirely trivial, as long as support for destruction/garbage-collection as a trigger is 100% guaranteed across platforms.
那时,只要在平台上 100% 保证对销毁/垃圾收集作为触发器的支持,就可以在对象上编写一个析构函数方法来减少计数器可能完全是微不足道的。
The only way to currently, reliably do it might be something like creating an enclosed registry of all created instances, and then manuallydestructing them (otherwise, they will NEVER be garbage-collected).
当前,可靠地执行此操作的唯一方法可能是创建所有已创建实例的封闭注册表,然后手动销毁它们(否则,它们将永远不会被垃圾收集)。
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
Will this pattern do what you want it to do? As long as:
这个模式会做你想让它做的事吗?只要:
- you don't turn
a
into something else - you don't overwrite its
explode
method - you don't mess with
Obj
in any way - you don't expect any
prototype
method to have access to any of the internal variables
- 你不会
a
变成别的东西 - 你不会覆盖它的
explode
方法 - 你不会以
Obj
任何方式惹恼 - 您不希望任何
prototype
方法可以访问任何内部变量
...then yes, this method will work just fine for having the counter work properly.
You could even write a general method called recycle
, which calls the explode
method of any object you pass it (as long as its constructor, or factory, supported such a thing).
...那么是的,这种方法可以很好地使计数器正常工作。您甚至可以编写一个名为 的通用方法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; }
}
Note - this won't actually get rid of the object. You'll just have removed it from the closure, and removed all methods/properties it once had.
注意 - 这实际上不会摆脱对象。您只需从闭包中删除它,并删除它曾经拥有的所有方法/属性。
So now it's an empty husk, which you could reuse, expressly set to null
after recycling its parts, or let it be collected and forget about it, knowing that you removed necessary references.
所以现在它是一个空壳,你可以重新使用它,null
在回收它的部分后明确设置它,或者让它被收集并忘记它,知道你删除了必要的引用。
Was this useful? Probably not.
这有用吗?可能不是。
The only time I really see this as being of use would be in a game where your character might only be allowed to fire 3 bullets at a time, and he can't shoot a 4th until the 1st one on screen hits someone or goes off the edge (this is how, say, Contra worked, in the day).
我唯一真正认为这是有用的时间是在游戏中,您的角色可能一次只能发射 3 发子弹,并且在屏幕上的第 1 发子弹击中某人或熄灭之前,他无法射击第 4 发边缘(这就是 Contra 在白天工作的方式)。
You could also just shift a "disappeared" bullet off the stack, and reuse that bullet for any player/enemy by resetting its trajectory, resetting appropriate flags, and pushing it back onto the stack.
您也可以将“消失”的子弹从堆栈中移出,然后通过重置其轨迹、重置适当的标志并将其推回堆栈来为任何玩家/敌人重复使用该子弹。
But again, until proxies allow us to define "magic" constructor/destructor methods, which are honoured at a low-level, this is only useful if you're going to micromanage the creation and destruction of all of your own objects (really not a good idea).
但是同样,直到代理允许我们定义“神奇”的构造函数/析构函数方法,这些方法在低级别受到尊重,这只有在您要微观管理所有自己的对象的创建和销毁时才有用(实际上不是一个好主意)。
回答by tainguyen723
My solution is creating an object store instance count and a function to increase them in prototype.
我的解决方案是创建一个对象存储实例计数和一个在原型中增加它们的函数。
function Person() {
this.countInst();
}
Person.prototype = {
constructor: Person,
static: {
count: 0
},
countInst: function() {
this.static.count += 1;
}
};
var i;
for (i = 0; i < 10; i++) {
var p = new Person();
document.write('Instance count: ');
document.write(p.static.count);
document.write('<br />');
}
Here is my plunker: https://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9?p=preview
这是我的 plunker:https://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9 ?p =preview