Javascript/AngularJS: 将函数绑定到每个对象还是制作辅助对象?
Javascript/AngularJS: Bind function to every object or make helper object?
只是一个快速的想法,我不知道如何google它。
如果你从 API 中得到一个 'persons' 的列表,格式为 AngularJS JSON,然后将其转换为 JS array/object :
[
{firstName: 'Foo', lastName: 'Bar'},
{firstName: 'Banana', lastName: 'Fruit'}
]
并且您需要一些将名字和姓氏连接到 fullName 中的通用函数。
那么通常认为使用解决方案 1 或 2 更好吗?
解决方案 1
数组由对象组成,这些对象本身具有所需的所有方法。
[
{firstName: 'Foo', lastName: 'Bar', fullName: function(){return this.firstName+' '+this.lastName;}},
{firstName: 'Banana', lastName: 'Fruit', fullName: function(){return this.firstName+' '+this.lastName;}}
]
我认为这是最 OOP 的解决方案,但在 Javascript(和长列表)的情况下也是最佳解决方案?
解决方案 2
制作只被实例化一次的辅助函数。
var helper = function(person)
{
return person.firstName+' '+person.lastName;
}
我知道这是非常基本的,但有时这是最正确的事情;)
在您的第一个解决方案中,您要为每个对象添加一个函数,这感觉很麻烦,如果您有很多对象并且迭代其他对象,我认为这不是最好的。
第二个更轻
另一个想法:
也许您可以将 JSON 解析为特定对象,例如此处:
Parse JSON String into a Particular Object Prototype in JavaScript
然后使用原型
Foo.prototype.fullname = function (){
return this.firstName+' '+this.lastName;
}
因此每个 Foo 对象都可以通过原型调用 fullname()(在内存中只调用一次 vs 在每个对象中)。
Boris Charpentier 已经为您提供了很好的答案。我可以添加一些示例代码:
可以通过原始 JSON 对象初始化自身的构造函数:
function Workout(workoutJson) {
if (workoutJson) {
this.duration = workoutJson.duration;
... // or copy all properties in a for-loop
}
}
var fn = Workout.prototype;
// extend the prototype with some functions
fn.getSomeData = function () {
return this.onePart + ' ' + this.anotherPart;
};
// another smart solution: get properties (modern browser necessary)
Object.defineProperties(fn, {
durationMinutes: {
enumerable: true,
get: function () {
return roundMillisToMinutes(this.duration);
},
set: function (val) {
this.duration = val * 60000;
}
}
});
现在您有一个 属性 durationMinutes
,它的行为类似于真正的 属性,但由 getter 和 setter 函数组成。
让我们添加一些静态函数(不需要实例),稍后我们将使用它们将原始 JSON 对象转换为领域对象:
Workout.fromJson = function(workoutJson) {
return new Workout(workoutJson);
};
Workout.fromJsonArray = function(workoutJsonArray) {
return workoutJsonArray.map(Workout.fromJson);
};
在我的数据访问服务中,我将原始数据转换为我的域模型实例(在本例中为锻炼):
/**
* Get an overview list of all workouts.
* @returns {*} a promise resolving in an array of `Workout` objects
*/
function getOverview() {
var defer = $q.defer();
$http.get('/api/web/workouts?overview=1')
.success(function (data) {
defer.resolve(Workout.fromJsonArray(data));
}).error(function (response) {
defer.reject(response);
});
return defer.promise;
}
/**
* Get a single Workout by its `extId`.
* @param extId
* @returns {*} a promise resolving in the fetched workout
*/
function getByExtId(extId) {
return WorkoutRS.get({id: extId}).$promise.then(function (data) {
return $q.when(Workout.fromJson(data));
});
}
备注:我知道有更好的方法来处理 $q 承诺并进行一些链接而不是使用 $q。这是 Angular 的一些早期工作。这里的重点是在哪里以及如何将原始 JSON 数据转换为 JavaScript "constructed" 对象(在它们的 prototype
.
中使用辅助方法或属性
编辑
我在 Opinionated AngularJS 博客中找到了一篇关于此的有趣文章。
只是一个快速的想法,我不知道如何google它。
如果你从 API 中得到一个 'persons' 的列表,格式为 AngularJS JSON,然后将其转换为 JS array/object :
[
{firstName: 'Foo', lastName: 'Bar'},
{firstName: 'Banana', lastName: 'Fruit'}
]
并且您需要一些将名字和姓氏连接到 fullName 中的通用函数。
那么通常认为使用解决方案 1 或 2 更好吗?
解决方案 1 数组由对象组成,这些对象本身具有所需的所有方法。
[
{firstName: 'Foo', lastName: 'Bar', fullName: function(){return this.firstName+' '+this.lastName;}},
{firstName: 'Banana', lastName: 'Fruit', fullName: function(){return this.firstName+' '+this.lastName;}}
]
我认为这是最 OOP 的解决方案,但在 Javascript(和长列表)的情况下也是最佳解决方案?
解决方案 2 制作只被实例化一次的辅助函数。
var helper = function(person)
{
return person.firstName+' '+person.lastName;
}
我知道这是非常基本的,但有时这是最正确的事情;)
在您的第一个解决方案中,您要为每个对象添加一个函数,这感觉很麻烦,如果您有很多对象并且迭代其他对象,我认为这不是最好的。
第二个更轻
另一个想法:
也许您可以将 JSON 解析为特定对象,例如此处:
Parse JSON String into a Particular Object Prototype in JavaScript
然后使用原型
Foo.prototype.fullname = function (){
return this.firstName+' '+this.lastName;
}
因此每个 Foo 对象都可以通过原型调用 fullname()(在内存中只调用一次 vs 在每个对象中)。
Boris Charpentier 已经为您提供了很好的答案。我可以添加一些示例代码:
可以通过原始 JSON 对象初始化自身的构造函数:
function Workout(workoutJson) {
if (workoutJson) {
this.duration = workoutJson.duration;
... // or copy all properties in a for-loop
}
}
var fn = Workout.prototype;
// extend the prototype with some functions
fn.getSomeData = function () {
return this.onePart + ' ' + this.anotherPart;
};
// another smart solution: get properties (modern browser necessary)
Object.defineProperties(fn, {
durationMinutes: {
enumerable: true,
get: function () {
return roundMillisToMinutes(this.duration);
},
set: function (val) {
this.duration = val * 60000;
}
}
});
现在您有一个 属性 durationMinutes
,它的行为类似于真正的 属性,但由 getter 和 setter 函数组成。
让我们添加一些静态函数(不需要实例),稍后我们将使用它们将原始 JSON 对象转换为领域对象:
Workout.fromJson = function(workoutJson) {
return new Workout(workoutJson);
};
Workout.fromJsonArray = function(workoutJsonArray) {
return workoutJsonArray.map(Workout.fromJson);
};
在我的数据访问服务中,我将原始数据转换为我的域模型实例(在本例中为锻炼):
/**
* Get an overview list of all workouts.
* @returns {*} a promise resolving in an array of `Workout` objects
*/
function getOverview() {
var defer = $q.defer();
$http.get('/api/web/workouts?overview=1')
.success(function (data) {
defer.resolve(Workout.fromJsonArray(data));
}).error(function (response) {
defer.reject(response);
});
return defer.promise;
}
/**
* Get a single Workout by its `extId`.
* @param extId
* @returns {*} a promise resolving in the fetched workout
*/
function getByExtId(extId) {
return WorkoutRS.get({id: extId}).$promise.then(function (data) {
return $q.when(Workout.fromJson(data));
});
}
备注:我知道有更好的方法来处理 $q 承诺并进行一些链接而不是使用 $q。这是 Angular 的一些早期工作。这里的重点是在哪里以及如何将原始 JSON 数据转换为 JavaScript "constructed" 对象(在它们的 prototype
.
编辑
我在 Opinionated AngularJS 博客中找到了一篇关于此的有趣文章。