Javascript mixin模式设置实例具体这个变量

时间:2013-07-22 14:23:29

标签: javascript oop mixins

如果我使用构造函数用于我的对象和原型用于共享功能,我想将共享功能(函数)混合到对象的原型,但是特定于实例(this变量)到对象实例。

要添加原型部件,我找到this pattern。为了设置原型函数假定存在的实例变量,我想出了一个init(每个mixin一个)。

这是一个简单的例子:

var mixIn=function(target,source){
  for(fn in source){
    if(source.hasOwnProperty(fn)){
      target.prototype[fn]=source[fn];
    }
  }
};
var SpeakEnable = {
  say:function(){
    console.log(this.message);
  },
  initSpeak:function(){// for initializing instance vars
    this.message="Hello World Mixed in!";
    this.object=[];
  }
};
var Person=function(){
  this.initSpeak();//have to init instance vars
};
// set up inheritance
// set up Person.prototype
// set speak enable
mixIn(Person,SpeakEnable);

var lulu=new Person();
lulu.say();

var june=new Person();
console.log(june.say===lulu.say);//true
console.log(june.object===lulu.object);//false

这一切都很好,花花公子,但初始化实例变量是我遇到问题的地方。它在某种程度上似乎不是一个非常干净的方式。当我混合使用几个mixin时,Person构造函数必须调用所有init函数来设置实例变量。忘记调用它将导致奇怪的错误(在这种情况下,在实例上调用say时控制台记录未定义)。

所以问题是:有没有更简洁的方法来设置mixin函数假设的初始实例变量?

1 个答案:

答案 0 :(得分:1)

您可以从基础对象继承所有可混合对象,以确保正确初始化。这是实现目标的一种干净方式。

以下代码演示了这一原则:

//------------ framework

var inherits = function(childCtor, parentCtor) {
  function tempCtor() {};
  tempCtor.prototype = parentCtor.prototype;
  childCtor.superClass_ = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  childCtor.prototype.constructor = childCtor;
};

var mixIn=function(target,source){
  for(fn in source){
    if(source.hasOwnProperty(fn) && fn.name != 'init'){
      target.prototype[fn]=source[fn];
    }
  }

  if (typeof source.init == 'function') { 
      if (target.prototype._mixInits === undefined) { 
          target.prototype._mixInits = [];
      }
      target.prototype._mixInits.push(source.init);
  }
};

// all objects that can be mixin's should inherit from
// this object in order to ensure proper initialization
var Mixable = function() {
    var mixInits = this.__proto__._mixInits;
    if (mixInits !== undefined) {
        for (var i = 0; i < mixInits.length; i++) {
            mixInits[i].call(this);
        }
    }
};

//------------ testcode

var SpeakEnable = {
  say:function(){
    console.log(this.message);
  },
  init:function(){
    console.log('say init called');
    this.message="Saying Hello World Mixed in!";
    this.object=[];
  }
};

var WalkEnable =  {
  walk:function(){
    console.log(this.walk_message);
  },
  init:function(){
    console.log('walk init called');
    this.walk_message="Walking step 1.2.3.";
  }
};


var Person=function() {
  Mixable.call(this);
};

inherits(Person, Mixable);

mixIn(Person,SpeakEnable);
mixIn(Person,WalkEnable);

var lulu=new Person();
lulu.say();
lulu.walk();