如何使用我可以推送的方法和数组创建一个Javascript类?

时间:2013-06-16 18:59:04

标签: javascript

我想定义一个管理消息的Javascript对象。在这个对象中,我需要一个我可以执行push()的数组:

MsgObjCollection.push(MsgObj)

基本上我试图用一堆MsgObjs填充MsgObjCollection对象。每个MsgObj都有3个变量messagesText,timeStamp,source(发送或接收)。

另外,我需要一些方法,如:

MsgObjCollection.Sent.Count       // Counts the number of sent messages
MsgObjCollection.Received.Count   // Counts the number of received messages
MsgObjCollection.Count            // Counts the total number of messages in the object

我不确定如何以最简单,最干净的方式解决这个问题。

注意:如果有任何混淆,这些不是静态方法。我将使用new运算符创建这些对象的实例。所以我需要多个实例

3 个答案:

答案 0 :(得分:2)

这是对bfavaretto's answer的一个调整,可以让你更接近你想要的东西:

function MsgObjCollection() {
    this.sent = [];
    this.received = [];
    this.total = [];

    this.push = function(msg) {
        // Assuming msg.source is either 'sent' or 'received',
        // this will push to the appropriate array.
        this[msg.source].push(msg);

        // Always push to the 'total' array.
        this.total.push(msg);
    };
};

您可以按如下方式使用:

var coll = new MsgObjCollection();
coll.push(/* whatever */);

var sent = coll.sent.length;
var received = coll.received.length;

如果需要,可以使用公开sent函数而不是received属性的对象包装Countlength数组;但这让我觉得没必要。

答案 1 :(得分:1)

您需要push,count,您可能希望拥有所有数组方法/访问器/迭代器。 更重要的是,如果你让你的收藏品成为阵列,你将获得一些速度提升。

所以最好的解决方案是继承数组,然后继承 让你的对象只是真正的数组:什么都不应该 在对象上定义,其原型上的一切。

- >>您将免费获得数组的速度和所有功能。

该功能如下:

function MsgObjCollection() { /* nothing */ };
var SO_pr =  ( MsgObjCollection.prototype = [] ) ;

然后,要在原型上定义count,发送和接收,使用Object.defineProperty不要污染枚举,也要使用getter / setter:

Object.defineProperty(SO_pr, 'sent', { get : function() { 
                          var cnt = 0; 
                          this.forEach( function(x) { if (x.source == 'Sent') cnt++; }); 
                          return cnt; } } );
Object.defineProperty(SO_pr, 'received', { get : function() { 
                           var cnt = 0; 
                           this.forEach( function(x) { if (x.source == 'Received') cnt++; });
                           return cnt; } } );
Object.defineProperty(SO_pr, 'count', { get  : function()   { return this.length } , 
                                        set  : function (x) { this.length = x    } });

请注意,由于Msg集合的原型是 new 数组,因此在更改MsgObjCollection的原型时不会污染数组的原型。

您希望的已发送和已接收属性更复杂:它们充当底层对象的视图 你可以做的一件事就是让它们返回一个由原始数组的正确项目构建的新数组 不过,我更喜欢在原始数组1)周围构建一个包装器,以允许通过此视图进行修改,以及2)避免垃圾创建。

小提琴在这里:http://jsfiddle.net/cjQFj/1/

Object.defineProperty(SO_pr, 'Sent',    
                      { get : function() { return getWrapper('Sent', this); } } ) ;
Object.defineProperty(SO_pr, 'Received', 
                      { get : function() { return getWrapper('Received', this); } } ) ;

function getWrapper(wrappedProp, wrappedThis) {
   var indx = 0, wp=null;
   // try to find a cached wrapper
   while (wp = getWrapper.wrappers[indx++] ) { 
           if (wp.wthis === this && wp.wprop==wrappedProp) return wp.wrapper;
   };
  // no wrapper : now build, store, then return a new one
  var newWrapper = { 
       get count() { return (wrappedProp=='Sent') ? wrappedThis.sent : wrappedThis.received },
       unshift : function () {  if (this.count == 0) return null;
                         var indx=0; 
                         while (wrappedThis[indx].source != wrappedProp ) indx++; 
                         var popped = wrappedThis[indx];
          while (indx<wrappedThis.length-1) {wrappedThis[indx]=wrappedThis[indx+1]; indx++; }
                         wrappedThis.length--;
                         return popped;
                       }
                 };
  getWrapper.wrappers.push({ wthis : wrappedThis, wprop : wrappedProp, wrapper :  newWrapper }); 
  return newWrapper;
};
getWrapper.wrappers = [];

现在进行一点测试:

var myColl = new MsgObjCollection();
myColl.push({ source : 'Sent', message : 'hello to Jhon' });
myColl.push({ source : 'Received' , message : 'hi from Kate' });
myColl.push({ source : 'Sent', message : 'hello to Kate' });
myColl.push({ source : 'Received' , message : 'Reply from Jhon' });
myColl.push({ source : 'Received' , message : 'Ho, i forgot from Jhon' });

console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + '  Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + '  Received.count ' + myColl.Received.count);
console.log('removing oldest sent message ');
var myLastSent = myColl.Sent.unshift();
console.log ('oldest sent message content : ' + myLastSent.message);
console.log('total number of messages : ' + myColl.count);
console.log('sent : ' + myColl.sent + '  Sent.count ' + myColl.Sent.count);
console.log('received : ' + myColl.received + '  Received.count ' + myColl.Received.count);

输出:&gt;&gt;

total number of messages : 5 
sent : 2  Sent.count 2 
received : 3  Received.count 3 
removing oldest sent message  
oldest sent message content : hello to Jhon
total number of messages : 4 
sent : 1  Sent.count 1 
received : 3  Received.count 3 

令人讨厌的部分是那些视图属性不是数组,但由于你不能重载[]运算符,你不能在原始数组上有一个完全透明的视图,(即:myBox.Sent [i]将是完全第i个发送的消息)所以在某些时候你可能想要动态创建数组进行某些操作。

答案 2 :(得分:0)

有几种方法可以做到这一点。如果你只需要一个实例,最简单的一个是对象文字:

var MsgObjCollection = {
    _arr : [],
    push : function(val) {
        return this._arr.push(val);
    },

    Sent : {
        Count : function() {
           // ...
        }
    },

    // etc.
};

如果您需要多个实例,请使用构造函数,并将方法添加到其prototype属性中:

function MsgObjCollection() {
    this._arr = [];
}
MsgObjCollection.prototype.push = function(val) {
    return this._arr.push(val);
}
MsgObjCollection.prototype.get = function(index) {
    return this._arr[index];
}
// and so on...

// USAGE:
var collection = new MsgObjCollection();
collection.push('foo');
console.log(collection.get(0));