簡體   English   中英

如何計算對象的實例?

[英]How can I count the instances of an object?

如果我有一個 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 時增加一個全局變量,這將是跟蹤這個計數器的唯一方法,但有什么比這個想法更好的方法嗎?

編輯:

看看這個作為這里的建議:

在此處輸入圖片說明

我的意思是我怎樣才能讓它回到 2 而不是 3

沒有任何內置的東西; 但是,您可以讓構造函數記錄它被調用的次數。 不幸的是,JavaScript 語言無法判斷對象何時超出范圍或已被垃圾回收,因此您的計數器只會上升,而不會下降。

例如:

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

當然,如果你想防止篡改計數,那么你應該通過閉包隱藏計數器並提供一個訪問器函數來讀取它。

[編輯]

根據您更新的問題 - 無法跟蹤實例何時不再使用或“刪除”(例如通過將 null 分配給變量),因為 JavaScript 沒有為對象提供終結器方法

您能做的最好的事情是創建一個“處理”方法,當對象不再活動時(例如通過引用計數方案),該方法將調用該方法,但這需要程序員的合作 - 該語言不提供任何幫助:

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

MyObj構造函數上創建一個名為 say count的靜態屬性,並在構造函數本身內增加它。

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

MyObj.count = 0;

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

alert(MyObj.count);

這是您通常在 Java 中執行的方式(使用靜態屬性)。

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}

使用ES6 Classes MDN語法 - 我們可以定義一個static方法:

static關鍵字定義了一個的靜態方法。 靜態方法在沒有實例化它們的類的情況下被調用,並且不能通過類實例調用。 靜態方法通常用於為應用程序創建實用程序函數。

 class Item { static currentId = 0; _id = ++Item.currentId; // Set Instance's this._id to incremented class's ID // PS: The above line is same as: // 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:如果您不想記錄 -公開內部currentId屬性,請將其設為私有

static #currentId = 0; 
_id = ++Item.#currentId;

這是一個帶有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

這樣的方法怎么樣?

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

保持全局計數變量並每次遞增是一種選擇。 另一種選擇是在每個實例創建后手動調用counter方法(我能想象的最糟糕的事情)。 但是還有另一個更好的解決方案。
每次我們創建一個實例時,都會調用構造函數。 問題是為每個實例創建構造函數,但我們可以在__proto__有一個count屬性,每個實例都可以相同。

function MyObj(){
    MyObj.prototype.addCount();
};

MyObj.prototype.count = 0;

MyObj.prototype.addCount = function() {
    this.count++;
};

var a = new MyObj();
var b = new MyObj();

畢竟這是我們的ab變量:

在此處輸入圖片說明

最終,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'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

這個模式會做你想讓它做的事嗎? 只要:

  1. 你不會把a變成別的東西
  2. 你不會覆蓋它的explode方法
  3. 你不會以任何方式Obj
  4. 您不希望任何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 在白天工作的方式)。

您也可以將“消失”的子彈從堆棧中移出,然后通過重置其軌跡、重置適當的標志並將其推回堆棧來為任何玩家/敵人重復使用該子彈。

但同樣,直到代理允許我們定義“神奇”的構造函數/析構函數方法,這些方法在低級別受到尊重,這只有在您要微觀管理所有自己對象的創建和銷毀時才有用(實際上不是一個好主意)。

我的解決方案是創建一個對象存儲實例計數和一個在原型中增加它們的函數。

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

這是我的 plunker: https ://plnkr.co/edit/hPtIR2MQnV08L9o1oyY9 ? p = preview

        class Patient{
        
        constructor(name,age,id){        
            Object.assign(this,{name, age, id});    
            
        }
        static patientList = []; // declare a static variable
        static addPatient(obj){       
            this.patientList.push(...obj); // push to array
            return this.patientList.length; // find the array length to get the number of objects
        }
        
    }
    
    let p1 = new Patient('shreyas',20, 1);
    let p2 = new Patient('jack',25, 2);
    let p3 = new Patient('smith',22, 3);
    let patientCount = Patient.addPatient([p1,p2,p3]); // call static method to update the count value with the newly created object
   console.log(Patient.patientList);
    console.log(patientCount);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM