Как я могу подсчитать экземпляры объекта?

Если у меня есть объект Javascript, определенный как:

function MyObj(){};

MyObj.prototype.showAlert = function(){
   alert("This is an alert");
   return;
};

Теперь пользователь может называть его как:

var a = new MyObj();
a.showAlert();

До сих пор так хорошо, и в том же коде можно также запустить другой экземпляр этого:

var b = new MyObj();
b.showAlert();

Теперь я хочу знать, как я могу удержать количество экземпляров MyObj? есть ли встроенная функция?

Один из моих соображений заключается в том, чтобы увеличить глобальную переменную, когда MyObj инициализирован, и это будет единственный способ отслеживать этот счетчик, но есть ли что-то лучше этой идеи?

EDIT:

Взгляните на это как предложение здесь:

enter image description here

Я имею в виду, как я могу заставить его вернуться к 2 вместо 3

Ответ 1

Нет ничего встроенного; Тем не менее, вы могли бы использовать функцию конструктора, чтобы подсчитать, сколько раз она была вызвана. К сожалению, язык JavaScript не дает возможности сказать, когда объект вышел из сферы действия или был собран мусор, поэтому ваш счетчик будет только подниматься, никогда не опускаться.

Например:

function MyObj() {
  MyObj.numInstances = (MyObj.numInstances || 0) + 1;
}
new MyObj();
new MyObj();
MyObj.numInstances; // => 2

Конечно, если вы хотите предотвратить фальсификацию счета, вы должны скрыть счетчик через закрытие и предоставить функцию доступа для его чтения.

[изменить]

В соответствии с вашим обновленным вопросом - нет способа отслеживать, когда экземпляры больше не используются или не удаляются (например, присваивая значение null переменной), поскольку JavaScript не предоставляет методы финализации для объектов.

Лучшее, что вы можете сделать, это создать метод "dispose", который вызовут объекты, когда они больше не активны (например, с помощью подсчета ссылок схема), но для этого требуется сотрудничество программиста - язык не оказывает никакой помощи:

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

Ответ 2

Создайте статическое свойство в конструкторе MyObj, называемом say count, и увеличьте его внутри самого конструктора.

function MyObj() {
    MyObj.count++;
}

MyObj.count = 0;

var a = new MyObj;
var b = new MyObj;

alert(MyObj.count);

Так вы обычно делаете это в Java (используя статическое свойство).

Ответ 3

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}

Ответ 4

как насчет такого метода?

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();           

Ответ 5

В качестве опции можно сохранить глобальную переменную count и увеличивать ее каждый раз. Другой вариант - вызывать метод 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();

В конце концов, это наши переменные a и b:

enter image description here

Ответ 6

В конце концов, у 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;

}());


// usage:

var a = new Obj("Dave"),
    b = new Obj("Bob"),
    c = new Obj("Doug");

Obj.count; // 3

// "Dave? Dave 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 memory
           // the horrors of memory-management, all over again

Будет ли этот шаблон делать то, что вы хотите? Пока:

  • вы не превращаете a во что-то другое
  • вы не перезаписываете свой explode метод
  • Вы не входите в Obj любым способом
  • вы не ожидаете, что какой-либо метод prototype получит доступ к любой из внутренних переменных

... тогда да, этот метод будет работать нормально, если счетчик работает правильно. Вы даже можете написать общий метод под названием recycle, который вызывает метод explode любого объекта, который вы передаете ему (если его конструктор или factory, поддерживал такую ​​вещь).

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 пули за раз, и он не может снимать 4-й, пока 1-й на экране не ударит кого-то или уходит с края (вот как, скажем, работал Контра, в день).

Вы также можете просто сместить "пропавшую" пулю со стека и повторно использовать эту пулю для любого игрока/врага, сбросив ее траекторию, сбросив соответствующие флаги и вернув ее обратно в стек.

Но опять же, пока прокси-серверы не позволят нам определить "магические" методы конструктора/деструктора, которые выполняются на низком уровне, это полезно только в том случае, если вы собираетесь миксонировать создание и уничтожение всех ваших собственных объектов (действительно не очень хорошая идея).

Ответ 7

Мое решение создает экземпляр экземпляра хранилища объектов и функцию для их увеличения в прототипе.

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 />');
}

Вот мой плукер: https://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9?p=preview