# Prototype inheritance with Knockout observables

I'm trying to write a JavaScript library to allow inheritance with knockout.

The fundamental problem when implementing inheritance in Knockout is that each Knockout observable is its own instance, thus if you try this:

 x = function () {};
x.prototype.m = ko.observable();
y = function () {};
y.prototype = new x();
z = new y();
//z.m == y.prototype.m == x.prototype.m


The behavior I'm trying to get goes like this:

//psudo-code, I know this wouldn't work
x = function () {};
x.prototype.a = ko.observable();
y = function () {};
y.prototype = new x();
y.prototype.b = ko.computed(function () { return this.a() });
//enabling this:
z = new y();
z.a(5);
a = new y();
a.a(12);
// z.b() == 5, a.b() == 12


Here's my proposed solution:

var getParams = function (args, index) {
return args.length > index + 1 ? Array.prototype.slice.apply(index) : Array.prototype.concat.call([], args[index])
};

var Ladder = function () {};

var self = this;
if (!(config instanceof dontInit)) {
// Only initialize if config is passed, this allows us to create sub-prototypes
if (this.attachEntity) this.entity = config;
for (var prop in self) {
var extender = self[prop];
if (extender instanceof doAttach) {
self[prop] = extender.extender.apply(self, extender.args); // || ('' + extender.extender); // if the function doesn't return a value perhaps it only performs operations? Leave a tatle tale behind?
}
}
if (this.populateObject) {
for (var prop in config) {
if (config.hasOwnProperty(prop)) {
var val = config[prop];
if (ko && ko.isObservable(self[prop])) self[prop](ko.unwrap(val));
else self[prop] = val;
}
}
}
for (var prop in self) {
var extender = self[prop];
if (extender instanceof doExtend) {
self[prop] = extender.extender.apply(self, extender.args); // || ('' + extender.extender); // if the function doesn't return a value perhaps it only performs operations? Leave a tatle tale behind?
}
}
}
}

Ladder.prototype.attach = function (propertyName, extender) {
var args = getParams(arguments, 2);
this.prototype[propertyName] = new doAttach(extender, args);
}

Ladder.prototype.extend = function (propertyName, extender) {
var args = getParams(arguments, 2);
this.prototype[propertyName] = new doExtend(extender, args);
}

var ctor = function (config) {
this.init(config);
};
ctor.prototype = new this(new dontInit());
return ctor;
};

return duplicatePrototypes(prototypes);
}

var dontInit = function () {};

// doAttach is called before config and should attach a computed or observable, though you may attach any value you like.
var doAttach = function (extender, args) {
this.extender = extender;
this.args = args;
};
var doComputed = function (computed) {
return new doExtend(function () {
return ko.computed(computed, this);
}, []);
};
// doExtend is called after config and would normally perform some init work
// naming convention for extenders is _00Name where 00 is a priority (00 will run before 01) and Name is a descriptive name
var doExtend = function (extender, args) {
this.extender = extender;
this.args = args;
};


My questions are:

1. Are there performance issues with this type of inheritance? i.e. if I use this paradigm to build complex objects with long inheritance chains, will there be a performance hit vs some other 'better' inheritance paradigm?

2. Does this make for clear code? Is it obvious what is going on when I define an object like this:

var myObject = usefullBaseClass.inherit();
myObject.attach("newProperty", ko.observable, 5);

var instanceOfMyObject = new myObject();

// instanceOfMyObjecct is an instance of myObject and has an observable
// property called newProperty which is unique to this instance

• I am most curious, what would you be modeling that requires a long inheritance chain ? I have yet to find something that requires more than 3 levels. – konijn Apr 1 '14 at 23:32
• My current use case consists of a set of base classes used to generate a grid, I then create inherited classes for each instance of the grid, the user is then able to extend the classes for grid A without affecting the behavior of those classes in grid B (the goal is for a very customizable grid). The current paradigm would only involve 2-3 deep chains, but that will likely change as I continue adding features. For example the Row class will likely be extended by a sub-class AggRow, when a sub-class AggRow is created for an individual grid it will have an inheritance chain 3 deep. – cwohlman Apr 2 '14 at 1:58
• I'd also like to plan for deeper inheritance if I can. – cwohlman Apr 2 '14 at 2:03
• Good enough, can you update the snippet under 'Does this make for clear code', the snippet should include how you created the usefullBaseClass. – konijn Apr 3 '14 at 13:05

Interesting question,

• Are there any performance hits ? I don't see problems, it would not be slower then building the objects in an old skool manner

• Does this make for clear code? Your sample code would not run, you need to provide a sample that would actually run.

Furthermore:

• You should run you code through JsHint
• You are missing semicolons
• You are declaring some variables more than once in the same function
• Your code has Ladder.prototype.attachComputed // doComputed <- Pointless
• Your code has return duplicatePrototypes(prototypes); <- duplicatePrototypes is not provided
• dontInit <- doNotInit reads better, also there must be a better way to avoid initialization ;)
• doAttach is a constructor, so definitely wrongly named. AttachedValue mayhaps?
• Anonymous functions are a pain in stacktraces, if you are going to create a custom OO approach, then I would avoid avoid anonymous functions like the plague.
• // naming convention for extenders is _00Name where 00 is a priority <- I do not believe this works, for (var prop in self) { does not pre-sort property names, at least that is not guaranteed
• The distinction between doAttach and doComputed is unclear, are the comments possibly out of date? // doAttach is called before config and should attach a computed or observable <- It seems from the code that I would attach a computable through doComputed ?
• This:

//Note: extender.extender might simply return undefined
self[prop] = extender.extender.apply(self, extender.args);


is better than

self[prop] = extender.extender.apply(self, extender.args); // || ('' + extender.extender); // if the function doesn't return a value perhaps it only performs operations? Leave a tatle tale behind?

• I guess var self = this; comes from your knockout background. If you are not using closures, then there is no good reason to use this.
• Do not drop newlines from if statements;

if (ko && ko.isObservable(self[prop]))
self[prop](ko.unwrap(val));
else
self[prop] = val;

• if (ko) should be at the very start of your script, there is no point if knockout is not available

All in all, I think I would not use your library until it has matured a bit more.