1

オブジェクトの配列を表すJSONを返すWebサービスを呼び出すWebアプリケーションがあります。各オブジェクトにはいくつかのフィールドがあります。アイデアを与えるためのJSONの例を次に示します。

{
   "data": [
      {
         "id": "12345",
         "from": {
            "name": "John Doe",
            "id": "6789"
         },
         "start_time": "2012-12-16T02:17:20+0000",
         "end_time": "2012-12-16T02:17:20+0000",
         "publish_time": "2012-12-16T02:17:20+0000"
         }
      },
      {
         "id": "8888",
         "from": {
            "name": "Jane Smith",
            "id": "011"
         },
         "start_time": "2012-12-16T02:17:20+0000",
         "end_time": "2012-12-17T02:17:20+0000",
         "publish_time": "2012-12-16T02:17:20+0000"
         }
      }
   ]
  }

これが戻ってきたら、jQueryのparseJSON()メソッドを使用して、これをオブジェクトの配列に拡張します(「データ」値を保持します)。それはすべて問題ありませんが、配列を取得した後、各配列スロットで動作できるいくつかの関数があります。たとえば、end_timeとstart_timeの間の時間経過を出力するGetDuration()という関数があるとします。いずれにせよ、私はいくつかの関数(おそらく15)を定義し、この時点で、配列全体を反復処理し、関数のコピーですべてのオブジェクトを膨らませます。例

for (var i=0;i<data.length;i++)
 data[i].TimeLapse = function() { ... };

これはもっと効率的にできると思います。今のところ、配列項目ごとに同じ関数の個別のコピーがあると思いますが、これは必須ではありません。また、処理時間の遅れにも気づきましたが、これを短縮できると期待しています。この状況で役立つと思われるjavascriptクロージャについて読んだことがありますが、クロージャで関数を記述した経験はあまりありません。クロージャーを設定してから、JSONを変更して、クロージャー型のオブジェクトに何らかの形で膨らませることはできますか?または、今日行っているように通常のjavascriptオブジェクトに膨らませて、作成したクロージャを指すようにオブジェクトタイプを変更しますか?

任意の考えや提案をいただければ幸いです。

ありがとう...

-ベン

4

3 に答える 3

1

あなたが言っているのは、JSONを使用して、それぞれ独自のメソッドを持つさまざまな種類のオブジェクトのプロパティを設定したいということだと思いますか?あなたが何を求めているのか、あるいは現在何をしているのかは明らかではありません。しかし、私が正しければ、あなたは間違いなくそれを間違っています。

つまり、データに関数を追加しないでください。代わりに、作成時にデータを受け入れることができるメソッドを使用てクラスを作成してください。

// Constructor, accepts an object expected to have data about a user
var User = function(data) {

  // save a field from the passed in user data on this instance
  this.name = data.name;
};

// a method every User object will have that uses some bit of user data
User.prototype.sayHi = function() {
  alert('Hi, my name is ' + this.name);
};

// A place to put our new user objects
var users = [];

// An array of objects to iterate through
var jsonData = [
  {name: 'Joe'},
  {name: 'Sally'}
];

// Iterate through the array
for (var i = 0; i < jsonData.length; i++) {

  // make a user, passing the constructor the data object for that user
  users.push( new User(jsonData[i]) );
}

users[0].sayHi(); // alerts: "Hi, my name is Joe"
users[1].sayHi(); // alerts: "Hi, my name is Sally"
于 2012-12-31T23:51:50.503 に答える
1

他の人がコメントで書いているように、あなたが何を望んでいるかは明確ではありませんが、これはあなたが説明しているものに最も近いように聞こえます:

function make_duration_fun(x) {
    return function() { return GetDuration(x.start_time, x.end_time); };
}

次に、ループで次のことができます。

data[i].TimeLapse = make_duration_fun(data[i]);

期間関数は1つだけですが、呼び出すmake_duration_funたびに、同じ関数と異なるxバインディングを持つ新しいクロージャーを取得します。

于 2012-12-31T23:52:10.720 に答える
1
  1. データの各要素をループする必要がある場合は、各アイテムの期間を計算して、プロパティとして追加してみませんか?

  2. 各データオブジェクトのすべてのプロパティを新しいオブジェクトにコピーする場合は、そのオブジェクトのコンストラクターでプロトタイプを使用し、プロトタイプなどの関数を追加できますtimeLapse。次に、すべてのデータオブジェクトが配線され、プロトタイプの継承を介して機能します。しかし、これは多くの余分な作業であり、パフォーマンスが低下する可能性があります。

  3. ストレートJSONを使用する代わりに、JSONPまたは返されたコードが実行されるバリアントを使用できます。このようなもの:

    {
       "data": [
          new DataItem(
             12345",
             {
                "name": "John Doe",
                "id": "6789"
             },
             "2012-12-16T02:17:20+0000",
             "2012-12-16T02:17:20+0000",
             "2012-12-16T02:17:20+0000"
          ),
          // ... and so on ...
       ]
    }
    

    まっすぐなオブジェクト表記(コードの実行が禁止され、値を持つことのみが許可されます)ではなく、実行されるコードに注意する必要がありますが、安全に実行できると思います。たとえば、new DataItem()最終的なオブジェクトごとに配列を埋め込むと言う代わりに、それらをループして、ここの手法を使用して配列をオブジェクトに変換 しapplyキーワードを使用newしてアイテム配列を渡してDataItem、新しいプロトタイプを取得することができます。物体。

  4. 配列内の各項目に関数を追加すると、data理論的には必要以上のメモリが必要になる可能性があります。トレードオフする時間とスペースの量に応じて、他のオプションがあります。例えば:

    function ItemWrapper(dataobj) {
        for (key in dataobj) {
           if (!dataobj.hasOwnProperty(key)) { continue; }
           this[key] = dataobj[ky];
        }
        this.timeLapse = (new Date(this.end_time)).getTime() - (new Date(this.start_time)).getTime(); // assign simple static properties
    }
    
    ItemWrapper.prototype.dynamicFn = function () {
       return this.x - this.y; // changeable properties accessed as functions
    }
    
    var currentObj = new ItemWrapper(data[23]);
    console.log(currentObj.timeLapse); // static
    console.log(currentObj.dynamicFn()); //dynamic
    

    問題は、このラッピングを使用時に実行するのか、それとも解析時に実行するのかということです。解析時にこれを行うことは、実際には私の提案#2です。ただし、この提案は、特定のアイテムが必要な場合にのみ実行することをお勧めします。アイテムへのアクセスのパターンがわからないため、これは理想的ではないかもしれませんが、少なくともオプションです。

  5. 使用applyまたはcall

    function timeLapse() {
       return (new Date(this.end_time)).getTime() - (new Date(this.start_time)).getTime();
    }
    
    var Item16Elapsed = timeLapse.apply(data[16]);
    

    このように、あちこちに関数をアタッチしたり、オブジェクトを新しいプロトタイプに配線されたオブジェクトに変換したりすることはありませんが、少し異なる方法で呼び出す必要があります。

于 2013-01-01T00:48:59.310 に答える