Javascript创建动态对象类

时间:2016-06-23 19:04:32

标签: javascript angularjs

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}}。

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;
&#13;
&#13;