JS函数以及抽象类和原型

时间:2019-03-22 12:39:54

标签: javascript prototype

这是我的代码的简化版:

  function TextBox () {
    this.builddom = function () {
      // Building the text dom
    }
  }
  function ImageBox () {
    this.builddom = function () {
      // Building the image dom
    }
  }
  function Box (type) {
    var handler =
      (type ==  'text') TextBox  :
      (type == 'Image') ImageBox : null;
    if (handler) (handler).call (this);

    this.builddom = function () {
      // Here I would like to call the correct builddom function for the type.
    }
  }
  var textbox = new Box ('text');
  textbox.builddom ();

如果Box.builddom不存在,则工作正常,将调用与特定类型关联的builddom函数。但是我需要在Box中做一些常规的事情,然后调用特定的builddom。如果我为Box builddom命名为Box.dobuilddom,它也可以,但是会破坏对Boxes的通用访问。

我认为可以通过一些巧妙的原型操作来完成这项工作,但是我找不到它。

6 个答案:

答案 0 :(得分:2)

也许最好避免原型设计,而使用合成

function TextBox(box) {
  this.builddom = function() {    
    console.log('Building the text dom', box.props);
  }
}

function ImageBox(box) {
  this.builddom = function() {
    console.log('Building the image dom', box.props);
  }
}

function Box(props) {
  this.props = props;
  this.builddom = function() {
    throw new Error('unsupported function');
  }
}

var textbox = new TextBox(new Box({size:5}));
textbox.builddom();

答案 1 :(得分:1)

我不太了解这个概念。盒子只是某种容器。它不执行任何操作,而是创建一个新实例。您真正需要的是Box接口,但是js没有接口。您可以使用TypeScript ...

  function TextBox () {
    this.builddom = function () {
      // Building the text dom
    }
  }
  function ImageBox () {
    this.builddom = function () {
      // Building the image dom
    }
  }

  var container = {
    createBox: function (type){
        if (type == "text")
            return new TextBox();
        else if (type == "image")
            return new ImageBox();
        else
            throw new Error();
    }
  };

  var textbox = container.createBox('text');
  textbox.builddom();

如果您想包装对象,另一个选择是使用代理,但我认为这不是您的目标。

如果以后需要类型检查,则可以使用继承,但是没有多重继承,因此即使那样,您也无法模仿接口。顺便说一句。

  function Box (){}

  function TextBox () {}
  TextBox.prototype = Object.create(Box.prototype, {
    constructor:TextBox,
    builddom: function () {
      // Building the text dom
    }
  });

  function ImageBox () {}
  ImageBox.prototype = Object.create(Box.prototype, {
    constructor:ImageBox,
    builddom: function () {
      // Building the image dom
    }
  });

  var container = {
    createBox: function (type){
        if (type == "text")
            return new TextBox();
        else if (type == "image")
            return new ImageBox();
        else
            throw new Error();
    }
  };

  var textbox = container.createBox('text');
  console.log(
    textbox instanceof Box, 
    textbox instanceof ImageBox, 
    textbox instanceof TextBox
  );
  textbox.builddom();

答案 2 :(得分:0)

如果您想使用原型,可以像这样:

function TextBox(props) {
    this.props = props;
}

TextBox.prototype = {
    builddom: function () {
      // Building the text dom
      console.log("TextBox", this.props);
    }
}

function ImageBox(props) {
    this.props = props;
}

ImageBox.prototype = {
    builddom: function () {
      // Building the text dom
      console.log("ImageBox", this.props);
    }
}

function Box (type, props) {
  var handler = (type ==  'text') ? TextBox :
    (type == 'Image')  ? ImageBox : null;
  if (handler) {
     handler.call(this, props);
     Object.assign(this, handler.prototype);     
  }
}

var textbox = new Box ('text', {text: 'some'});
textbox.builddom ();

var imagebox = new Box ('Image', {x: 1, y: 2});
imagebox.builddom ();

答案 3 :(得分:0)

如果您不想使用Box类,则无需创建它,而是创建一个工厂函数并返回相应类的新实例。

function AbstractBox() {}
AbstractBox.prototype.builddom = function() {
  console.warn("unimplemented method");
};

function TextBox() {}
TextBox.prototype.builddom = function() {
  console.log("TextBox.builddom called");
};

function ImageBox() {}
ImageBox.prototype.builddom = function() {
  console.log("ImageBox.builddom called");
};

function ErrorBox() {}



function createBox(type) {
  var handler = Object.create(({
    "text": TextBox,
    "Image": ImageBox
  }[type] || ErrorBox).prototype);
  handler.constructor.apply(handler, [].slice.call(arguments, 1));
  for (var property in AbstractBox.prototype) {
    var method = AbstractBox.prototype[property];
    if (typeof method === "function" && !(property in handler)) handler[property] = method;
  }
  return handler;
}

(createBox("text")).builddom(); // Text
(createBox("Image")).builddom(); // Image
(createBox("error")).builddom(); // Error

答案 4 :(得分:0)

目前尚不清楚为什么不只在这里使用标准原型继承。它将允许您继承或重写父方法。例如,ImageBox继承父方法,而TextBox覆盖:

/* Define Box */
function Box (type) {
    this.type = type || 'box'
}
Box.prototype.builddom = function (){
    console.log(this.type, ": build called")
}

/* Define TextBox */
function TextBox () {
    Box.call(this, "text")
}
TextBox.prototype = Object.create(Box.prototype);

/* Override method */
TextBox.prototype.builddom = function (){
    // call parent method too?
    // Box.prototype.builddom.call(this)
    console.log(this.type, "Text box override method")
}

/* Define ImageBox */
function ImageBox () {
    Box.call(this, "image")
}
ImageBox.prototype = Object.create(Box.prototype);


var box = new Box ();
box.builddom();

var textbox = new TextBox ();
textbox.builddom();

var imageBox = new ImageBox ();
imageBox.builddom();

答案 5 :(得分:0)

我的建议是使用组合/委托而不是继承(用-a代替is-a)。

function TextBox () {
    this.builddom = function () {
      // Building the text dom
    }
  }
  function ImageBox () {
    this.builddom = function () {
      // Building the image dom
    }
  }
  function Box (type) {
    var constructor =
      (type ==  'text') ? TextBox  :
      (type == 'Image') ? ImageBox : null;
    var delegate = new constructor();

    this.builddom = function () {
      // Pre-work goes here.
      delegate.builddom();
      // Post-work goes here.
    }
  }
  var textbox = new Box ('text');
  textbox.builddom ();