JS TOOLS
Angular 1.5.x& lodash 4.x
问题
我正在尝试创建一个创建对象/类的对象工厂模式。在下面的示例中,我将为内容类型创建对象模型,例如文章,文档,图像等鉴于我的技能限制,我正在为每种内容类型复制下面的文章示例。在JavaScript中有没有办法用独特的原型创建动态对象类。
CURRENT APPROACH
// constructor injection
_Constructor.$inject = [];
function _Constructor() {
function __constructor(data, keys) {
_.assign(this, _.pick(data, keys));
}
return __constructor;
}
// one of many content type models
Article.$inject = ['__constructor'];
function Article(__constructor) {
function Article(data) {
var fillables = Object.freeze(['id','title','subtitle','body','body']);
__constructor.call(this, data, fillables);
}
Article.prototype = Object.create(__constructor.prototype);
Article.prototype.constructor = Article;
return Article;
}
IDEAL OUTCOME
创建一个内容类型模型工厂模式,允许我创建唯一的内容类型对象模型。伪示例:
var documentFillables = Object.freeze(['id', 'name', 'body']),
documentData = {id:1,name:'My Document', body: 'coolbody stuff'},
Document = new ModelFactory('Document', documentData, documentFillables),
articleFillables = Object.freeze(['id', 'title', 'subtitle']),
articleData = {id:1,title:'My Article', subtitle: 'My Subtitle'},
Article = new ModelFactory('Article', articleData, articleFillables);
注意我已经使用了合并,扩展和克隆,虽然我可以复制和扩展对象但最终会有相当多的代码冗余和/或通用对象,即有很多ModelFactory()
但没有{{ 1}}。
答案 0 :(得分:1)
您可以创建一个服务(一个返回构造函数的工厂),这对所有文档类型都是通用的。
在该函数内部,您可以使用angular.extend
扩展传递数据的默认值。
还要注意命名,例如:不要使用document
来避免与浏览器文档对象发生命名冲突。这就是我将其命名为myDocument
的原因。
要创建扩展工厂,您可以在工厂函数中使用依赖注入并扩展基础(请参阅imageService
的代码)。
请查看下面的演示或此jsfiddle。
angular.module('demoApp', [])
.factory('content', ContentService)
.factory('article', ContentService)
.factory('myDocument', ContentService)
.factory('myImage', imageService)
.controller('mainController', MainController);
function MainController(article, myDocument, myImage) {
console.log(new article({
title: 'Test'
}));
console.log(new myDocument({
title: 'second'
}));
console.log(new myImage({
title: 'image'
}));
var newImage = new myImage({
title: 'placeholder img',
src: 'https://placehold.it/300'
});
console.log(newImage);
this.newImage = newImage;
}
function generateUUID() {
var d = new Date().getTime();
if (window.performance && typeof window.performance.now === "function") {
d += performance.now(); //use high-precision timer if available
}
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
return uuid;
}
/*
// base not really needed, just as example
function base(options) {
angular.extend(this, {
id: generateUUID(),
title: '',
subtitle: '',
body: ''
}, options);
}*/
function ContentService() {
return function(options) {
//base.call(this, options);
angular.extend(this, {
id: generateUUID(),
title: '',
subtitle: '',
body: ''
}, options);
};
}
function imageService(content, $window) {
return function(options) {
var contentFactory = new content(options);
angular.extend(contentFactory, {
example: function() {
$window.alert('extended service: ' + contentFactory.title);
}
});
return contentFactory;
}
}

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<h3>
click image to test extended content class
</h3>
<img ng-src="{{ctrl.newImage.src}}" ng-click="ctrl.newImage.example()" />
<p>
{{ctrl.newImage.title}}
</p>
</div>
&#13;