我有一个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对象,就像我今天所做的那样,并以某种方式通过并更改对象类型以指向我创建的闭包?
任何想法或建议都将不胜感激。
...谢谢
-Ben
答案 0 :(得分: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"
答案 1 :(得分: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
绑定的新闭包。
答案 2 :(得分:1)
如果您必须遍历每个数据元素,为什么不计算每个项目的持续时间并将其添加为属性?
如果您愿意将每个数据对象的所有属性复制到一个新属性,则可以在该对象的构造函数上使用原型,并将timeLapse
等函数添加到原型中。然后,所有数据对象都通过原型继承连接起来。但这是一项额外的工作,而且可能无法提高效率。
您可以使用JSONP或执行返回代码的变体,而不是使用直接JSON。像这样:
{
"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()
为每个最终对象嵌入一个数组,然后循环遍历它们并使用the technique here apply
将new
转换为对象{{1} }}关键字并将项数组传递给DataItem
以获取新的原型有线对象。
向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。但是这个建议只有在你需要一个特定的项目时才会这样做。我不知道您的物品访问模式,所以这可能不太理想,但它至少是一个选项。
使用apply
或call
:
function timeLapse() {
return (new Date(this.end_time)).getTime() - (new Date(this.start_time)).getTime();
}
var Item16Elapsed = timeLapse.apply(data[16]);
这样你就不会在任何地方附加功能,你不会将对象转换为新的原型有线对象,但你必须以不同的方式调用它们。