Javascript 对象文字内部的工厂模式,以实现可编辑性和反射性

Javascript 对象文字内部的工厂模式,以实现可编辑性和反射性,javascript,Javascript,我希望能够从工厂构造实例,并使它们看起来像由new Instance()创建的实例——这意味着构造函数和原型与由new创建的实例无法区分 工厂将驻留在一个对象文本中,因此它的调用看起来像 var instance=App.factory.Instance.create(arg1,...); 请注意,“classname”的“Instance”并没有传递给泛型创建者 另一个要求是该实例的成员驻留在对象文本中,如果没有提供构造函数,则使用默认值(无操作) 驻留在文本中的成员是为了迭代和反射的目的,

我希望能够从工厂构造实例,并使它们看起来像由
new Instance()
创建的实例——这意味着构造函数和原型与由
new
创建的实例无法区分

工厂将驻留在一个对象文本中,因此它的调用看起来像

var instance=App.factory.Instance.create(arg1,...);
请注意,“classname”的“Instance”并没有传递给泛型创建者

另一个要求是该
实例的成员驻留在对象文本中,如果没有提供构造函数,则使用默认值(无操作)

驻留在文本中的成员是为了迭代和反射的目的,这就是为什么任何在空白中进行处理的方法都不起作用的原因

/* 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);
我让它工作了一半,但我感到困惑,并在基本方法上寻求改进。此外,我是否缺少任何可以使
实例
与经典构造对象区分开来的连线

拓宽这一思路,似乎应该有一个库,它将采用这种模板并生成工厂,其中类通过
对象.defineProperty
构造,从而提供更多的控制-即
\u readonly
等。一种语言中的一种语言

如果您稍后创建一个函数,其
名称
等于
\u name
,该函数只调用
ctor
,就像这样调用
ctor.call(this)

看起来,为了对
实例不可知,您添加了
\u name
约定。您还可以创建一个函数,该函数接受
应用程序
对象,并递归添加
\u name
字段。另一种可能是将
工厂
而不是
实例
传递给将要添加
创建
方法的函数

that._ctor.name=that._name;
此代码不执行任何操作,因为函数的名称是只读属性。它也不需要,因为代码
eval('(函数'+that.\u name+'(){})
已经用您想要的名称创建了函数

fn.prototype.constructor=fn
当您声明一个函数时,它会自动获取一个原型,并将构造函数字段设置为该函数。您必须使用
rv.constructor.prototype.constructor=that设置原型的构造函数字段因为您用模板替换了原型。您可以在
rv=new that.之前或之后执行此操作

这就是让工厂创建的对象与正常创建的对象区别开来的原因。为了使
instanceof
操作符工作
App.factory.Instance
需要是构造函数

下面是我根据您的要求编写的代码

App={
工厂:{
实例:{
模板:{
c:3,
d:4
},
_静态:{
e:5,
f:6
},
构造函数:函数(a,b){
这个a=a;
这个.b=b;
}
}
}
};
函数初始化(工厂){
for(工厂中的变量名称){
var构造函数=eval('(函数'+name+'(){}');
constructor.prototype=factory[name]。模板;
Object.defineProperty(constructor.prototype,'constructor'{
值:构造函数,
可枚举:false
});
for(工厂中的var属性[名称]。\u静态){
构造函数[属性]=工厂[名称]。_静态[属性];
}
var previous=工厂[name]。构造函数;
var create=函数(){
var实例=新构造函数();
如果(先前){
previous.apply(实例、参数);
}
返回实例;
}
工厂[名称]=建造商;
工厂[名称]。创建=创建;
}
}
初始(应用程序工厂);
经典函数(a,b){
这个a=a;
这个.b=b;
};
Classic.prototype.c=3;
Classic.prototype.d=4;
经典。e=5;
经典。f=6;
var classic=新classic(1,2);
var instance=App.factory.instance.create(1,2);
console.log('classic',classic);
log('instance',instance);
log('classic.constructor',classic.constructor);
log('instance.constructor',instance.constructor);
log('instance.constructor.name',instance.constructor.name);
log('classic.constructor.name',classic.constructor.name);
log('classic instanceof classic',classic instanceof classic);
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);
log('instance.a',instance.a);
log('instance.b',instance.b);
log('instance.c',instance.c);
log('instance.d',instance.d);
log('App.factory.Instance.e',App.factory.Instance.e');

log('App.factory.Instance.f',App.factory.Instance.f')如果没有找到任何库执行此操作,请将其作为一个标志。
that._ctor.name=that._name;
fn.prototype.constructor=fn
classic instanceof Classic
instance instanceof App.factory.Instance