Knockout JS Model Inheritance

2019-01-31 04:14发布

问题:

I have three relatively similar knockout models in my application and I would like to extend a base model to combine common properties rather than repeat myself three times.

example

var ItemModel = function (item) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);
};

var StandardItemModel = function (item, cartItemTypes) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);

  self.isInCart = ko.computed(function () {
    return cartItemTypes().indexOf(item.type) > -1;
  }, self);

  self.itemClass = ko.computed(function () {
     return self.isInCart() ? "icon-check" : "icon-check-empty";
  }, self);
};

var CustomItemModel = function (item) {
  var self = this;

  self.order = ko.observable(item.order);
  self.title = ko.observable(item.title);
  self.price = ko.observable(item.price);
  self.type = ko.observable(item.type);

  self.icon = item.icon;
};

I would like to use ItemModel as a base class and just add the extra properties as necessary.

回答1:

I think you can use ko.utils.extend like this

ko.utils.extend(self, new ItemModel(item));

inside the StandardItemModel

like this: http://jsfiddle.net/marceloandrader/bhEQ6/



回答2:

I guess you can do something like this:

var StandardItemModel = function (item, cartItemTypes) {
var self = this;
self.standard = new ItemModel(item);
self.isInCart = ko.computed(function () {
return cartItemTypes().indexOf(item.type) > -1;
}, self);

self.itemClass = ko.computed(function () {
 return self.isInCart() ? "icon-check" : "icon-check-empty";
 }, self);
}


回答3:

function MyBaseType() {
    var self = this;
    self.Id = 1
}

function MyComplexType() {
    var self = this;

    //Extending this class from MyBaseType
    ko.utils.extend(self, new MyBaseType());

    self.Name = 'Faisal';

    self.MyComplexSubType = new MyComplexSubType();
}

function MyComplexSubType() {
    var self = this;

    self.Age = 26;
}

JSFIDDLE EXAMPLE



回答4:

I've done something similar, with a lot of trial and error, but I got this to work for me:

var StandardItemModel = function (item, cartItemTypes) {
    var self = this;
    ItemModel.call(self, item)
}

You then need to add a prototyped constructor:

StandardModel.prototype = new ItemModel();

If you want to have common methods, then you need to add them to the base classes using prototype to add them, then call them in the higher class using:

ItemModel.prototype.methodName.call(self, parameters);


回答5:

You can chain constructor calls using .call or .apply

function ItemModel (item) {
    var self = this;

    self.order = ko.observable(item.order);
    self.title = ko.observable(item.title);
    self.price = ko.observable(item.price);
    self.type = ko.observable(item.type);
}

function StandardItemModel(item, cartItemTypes) {
    var self = this;

    ItemModel.call(this, item);

    self.isInCart = ko.computed(function () {
        return cartItemTypes().indexOf(item.type) > -1;
    }, self);

    self.itemClass = ko.computed(function () {
        return self.isInCart() ? "icon-check" : "icon-check-empty";
    }, self);
}

function CustomItemModel (item) {
    var self = this;

    ItemModel.apply(this, [item]);

    self.icon = item.icon;
}

The advantage over ko.utils.extend (or similar methods from jQuery, underscore, etc) is that you are not creating an additional object just to grab references to its methods.