对象文本内部的工厂模式,以实现可迭代性和反射性
Factory pattern inside object literal to accomplish iterability and reflection
我希望能够从工厂构建实例,并使它们看起来像new Instance()
创建的实例——这意味着构造函数和原型与new
创建的实例无法区分。
工厂将驻留在对象文字中,因此它的调用看起来像
var instance=App.factory.Instance.create(arg1,...);
请注意,"classname"Instance"不会传递给泛型创建者。
另一个要求是这个Instance
的成员驻留在对象文字中,如果没有提供构造函数,则使用默认值(没有op)。
驻留在文本中的成员是为了迭代和反思,这就是为什么任何在空白中解决问题的方法都不起作用。
/* jshint laxcomma: true */
window.App={
_name:'App'// convention
,factory:{
_name:'factory'
// begin specifying classes
,Instance:{ // this is a mini-factory of type 'Instance',
// a 'create' method is dynamically injected when 'factory' is initialized
_name:'Instance'
,ctor:function Instance(a,b){ // OPTIONAL specified constructor, want to ditch fn name here if possible
}
,template:{ // Instance spec container. Is like 'Instance.prototype'
//_name:'template' // convention, but will not be a member of 'instance'
valueMember:'something' // this will exist on finished 'prototype'
,funcMember:function(){ // this will exist on finished 'prototype'
}
}
,_static:{ // these will be placed on 'Instance' (constructor)
_name:'_static' // convention, but not placed
,valueMember:'something' // this will exist on 'Instance' (constructor)
,funcMember:function(){ // this will exist on 'Instance' (constructor)
}
}
//,create:function(){} is injected during init of factory
}// - Instance
// more classes like Instance here...
}
};
App.factory.Instance.create=function(){ // this must be generic/agnostic to 'Instance'
var that=this; // this is 'Instance:'
function init(){
if (that.ctor===undefined) { // user did not provide constructor
//that.ctor=new Function(''); // BAD WAY
// make a generic constructor with correct name
that.ctor=eval('(function '+that._name+'(){})');
}
// preserve constructor for reuse
that._ctor=that.ctor;
delete that.ctor;
var i;
if (typeof that._static==='object') { // put statics on constructor
for (i in that._static) {
if (i!=='_name') { // ignore convention
that._ctor[i]=that._static[i];
}
}
}
// doing it whole here, should be a cleaned-of-convention duplicate object
that._ctor.prototype=that.template;
that._ctor.name=that._name;
// this line confuses me, something should be done, do I need it?
//that._ctor.prototype.constructor=that._ctor; // produces 'constructor' in instance
}
// look in cache
if (that._ctor===undefined) {
init();
}
// NOW THE HARD PART - HOW TO INVOKE
var rv;
var fn=that._ctor;
//rv=construct(fn,arguments);
//rv= new fn();
rv=new that._ctor();
// HERE
// fn.prototype.constructor=fn;
// My problem at this point is getting instance.constructor to
// not be 'Object' but if I include the line above
// it shows 'constructor' as iterable
// however THIS LINE WORKS, but why? BUT Why do I have to do it here, after construction?
rv.constructor.prototype.constructor=that._ctor;
// NO that._ctor.prototype.constructor=that._ctor; puts 'constructor' on instance
return rv;
}; //-create
function Classic(a,b){
}
Classic.prototype.member="member";
var classic=new Classic();
var instance=App.factory.Instance.create();
console.log('classic',classic);
console.log('instance',instance);
console.log('classic.constructor',classic.constructor);
console.log('instance.constructor',instance.constructor);
console.log('instance.constructor.name',instance.constructor.name);
console.log('classic.constructor.name',classic.constructor.name);
我已经完成了一半,但我感到困惑,并希望在基本方法上有所改进。此外,我是否遗漏了任何可以使instance
与经典构造对象区分开来的接线?
扩展这一想法,似乎应该有一个库来接受这种模板化,并生成通过Object.defineProperty
构建类的工厂,从而提供更多的控制权,即_readonly
等。一种语言中的语言。
JSBin
,ctor:function Instance(a,b){ // OPTIONAL specified constructor, want to ditch fn name here if possible
如果稍后创建一个name
等于_name
的函数,只调用ctor
(如ctor.call(this);
),则可以在此处删除类的名称
App.factory.Instance.create=function(){ // this must be generic/agnostic to 'Instance'
看起来,为了不可知Instance
,您添加了_name
约定。您还可以创建一个函数来接受App
对象,并递归地添加_name
字段。另一种可能性是将factory
而不是Instance
传递给要添加create
方法的函数。
that._ctor.name=that._name;
此代码不执行任何操作,因为函数的名称是只读属性。也不需要它,因为代码eval('(function '+that._name+'(){})')
已经创建了具有所需名称的函数。
fn.prototype.constructor=fn
当您声明一个函数时,它会自动获得一个原型,其中构造函数字段设置为该函数。您必须用rv.constructor.prototype.constructor=that._ctor;
设置原型的构造函数字段,因为您用模板替换了原型。您可以在rv=new that._ctor();
之前或之后执行此操作。
classic instanceof Classic
instance instanceof App.factory.Instance
这将使工厂创建的对象与正常创建的对象区分开来。为了使instanceof
运算符工作,App.factory.Instance
需要是构造函数。
这是我根据您的要求编写的代码。
App = {
factory: {
Instance: {
template: {
c: 3,
d: 4
},
_static: {
e: 5,
f: 6
},
constructor: function (a, b) {
this.a = a;
this.b = b;
}
}
}
};
function init(factory) {
for (var name in factory) {
var constructor = eval('(function ' + name + '(){})');
constructor.prototype = factory[name].template;
Object.defineProperty(constructor.prototype, 'constructor', {
value: constructor,
enumerable: false
});
for (var property in factory[name]._static) {
constructor[property] = factory[name]._static[property];
}
var previous = factory[name].constructor;
var create = function () {
var instance = new constructor();
if (previous) {
previous.apply(instance, arguments);
}
return instance;
}
factory[name] = constructor;
factory[name].create = create;
}
}
init(App.factory);
function Classic(a, b) {
this.a = a;
this.b = b;
};
Classic.prototype.c = 3;
Classic.prototype.d = 4;
Classic.e = 5;
Classic.f = 6;
var classic = new Classic(1, 2);
var instance = App.factory.Instance.create(1, 2);
console.log('classic', classic);
console.log('instance', instance);
console.log('classic.constructor', classic.constructor);
console.log('instance.constructor', instance.constructor);
console.log('instance.constructor.name', instance.constructor.name);
console.log('classic.constructor.name', classic.constructor.name);
console.log('classic instanceof Classic', classic instanceof Classic);
console.log('instance instanceof App.factory.Instance', instance instanceof App.factory.Instance);
console.log('classic.a', classic.a);
console.log('classic.b', classic.b);
console.log('classic.c', classic.c);
console.log('classic.d', classic.d);
console.log('Classic.e', Classic.e);
console.log('Classic.f', Classic.f);
console.log('instance.a', instance.a);
console.log('instance.b', instance.b);
console.log('instance.c', instance.c);
console.log('instance.d', instance.d);
console.log('App.factory.Instance.e', App.factory.Instance.e);
console.log('App.factory.Instance.f', App.factory.Instance.f);
- 如何在javascript中迭代数字列表
- JS:检查URL中的参数,然后迭代一个参数为var的函数
- 如何迭代Array.prototype函数
- 如何使用jquery迭代具有相同属性的html元素并查找onclick事件
- 在ejs-partial中对JSON对象进行迭代
- 如何在DataTables 2.1中迭代对象数组
- 使用递归属性迭代保留属性结构
- 正在停止.在jquery中的特定时间间隔内,每次迭代的每次执行
- 如果30秒未单击,请应用CSS一次,将其删除,然后重新迭代
- 主干-从模板中迭代的集合中获取特定的模型
- 实现json迭代
- Javascript/Angularjs :等待承诺实现,然后再进入foreach Loop中的下一次迭代
- 了解实现自定义迭代器
- 如何实现此代码:Hashmaps,<s: 迭代器>
- 对象文本内部的工厂模式,以实现可迭代性和反射性
- 如何在多维数组上实现迭代器
- 如何实现迭代的、填充数组的Angular 2输入
- 迭代地实现归并排序
- 在JavaScript中实现对象属性的yield迭代器
- 如何在流星实现SimpleSchema中迭代包含对象的数组