1

我有一个 Web 应用程序,它调用一个 Web 服务,该服务返回一些表示对象数组的 JSON。每个对象都有一些字段。下面是一些示例 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() 方法将其膨胀为对象数组(保留“数据”值)。这一切都很好,但是在我拥有我的数组之后,我有几个可以在每个数组插槽上运行的函数。例如,假设有一个名为 GetDuration() 的函数将打印出 end_time 和 start_time 之间的时间间隔。无论如何,我定义了几个函数(可能是 15 个),此时,我只需遍历整个数组并使用函数的副本对每个对象进行膨胀。例子

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

我认为这可以提高效率。现在,我认为每个数组项都有一个相同函数的单独副本,这不是必需的。我还注意到处理时间的滞后,我希望可以减少。我读过关于 javascript 闭包的文章,在这种情况下它们似乎可以帮助我,但我没有太多在闭包中编写函数的经验。我会设置闭包然后修改 JSON 以某种方式膨胀到闭包类型的对象吗?或者我会像我今天所做的那样膨胀到常规的 javascript 对象,然后以某种方式通过并更改对象类型以指向我创建的闭包?

任何想法或建议将不胜感激。

谢谢...

-本

4

3 回答 3

1
  1. If you have to loop over each element of data, why not calculate the duration for each item and just add it as a property?

  2. If you're willing to copy all the properties of each data object to a new one, you could use a prototype on the constructor of that object, and add functions such as timeLapse to the prototype. Then all your data objects are wired up to work through prototypical inheritance. But this is a lot of extra work and may not be performant.

  3. Instead of using straight JSON, you could use JSONP or a variant where the returned code is executed. Something like this:

    {
       "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 ...
       ]
    }
    

    You do have to be careful about executed code as opposed to straight up object notation (which is prevented from executing code, it's only allowed to have values), but I believe it can be done safely. For example, you could instead of saying new DataItem() just embed an array for each final object, then loop over them and convert the arrays to objects using the technique here, applying with the new keyword and passing in the item array to DataItem to get a new prototype-wired object.

  4. Adding a function to each item in your data array could theoretically take more memory than necessary. Depending on how much time vs. space you want to trade off, there are other options. For example:

    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
    

    The question is: do you want to perform this wrapping at use time, or at parsing time? Doing this at parsing time is actually my suggestion #2. But this suggestion is to do it only when you need a particular item. I don't know your pattern of item access so this may not be ideal, but it is at least an option.

  5. Use apply or call:

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

    This way you're not attaching functions all over the place, you're not converting objects to new prototype-wired objects, but you have to call things a little differently.

于 2013-01-01T00:48:59.310 回答
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]);

只有一个持续时间函数,但每次调用make_duration_fun时都会得到一个具有相同函数和不同x绑定的新闭包。

于 2012-12-31T23:52:10.720 回答