1

メッセージを管理する Javascript オブジェクトを定義したいと考えています。このオブジェクト内で、push() を実行できる配列が必要になります。

MsgObjCollection.push(MsgObj)

基本的に、MsgObjCollection オブジェクトを多数の MsgObjs で埋めようとしています。各 MsgObj には、messageText、timeStamp、source (送信または受信) の 3 つの変数があります。

また、次のようなメソッドが必要になります。

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 演算子を使用して、これらのオブジェクトのインスタンスを作成します。したがって、複数のインスタンスが必要になります

4

3 に答える 3

2

これは、あなたが望むものに近づくはずのbfavarettoの答えの微調整です:

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

于 2013-06-16T19:22:08.603 に答える
1

プッシュ、カウントが必要です。すべての配列メソッド/アクセサー/イテレーターが必要になる場合があります。さらに、コレクションを配列にすると、速度が向上します。

したがって、最善の解決策は、配列から継承し、オブジェクトを実際の配列にすることです。オブジェクトには何も定義せず、すべてをプロトタイプに定義する必要があります。

-->> 配列の速度とすべての機能を無料で利用できます。

関数は次のようになります。

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

次に、プロトタイプで送受信されるカウントを定義するには、 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 コレクションのプロトタイプは新しい配列であるため、MsgObjCollection のプロトタイプを変更するときに配列のプロトタイプを汚染しないことに注意してください。

必要な Sent および Received プロパティはより複雑です。これらは、基になるオブジェクトのビューとして機能します。
できることの 1 つは、元の配列の適切な項目から構築された新しい配列を返すようにすることです。
ただし、元の配列の周りにラッパーを構築して、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);

出力 : >>

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 番目になります)。送信されたメッセージ) したがって、ある時点で、いくつかの操作のためにその場で配列を作成したい場合があります。

于 2013-06-16T22:48:19.933 に答える
0

それにはいくつかの方法があります。インスタンスが 1 つだけ必要な場合の最も単純なものの 1 つは、オブジェクト リテラルです。

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));
于 2013-06-16T19:03:53.140 に答える