Reputation: 28803
I'm writing some JavaScript classes (old school and NOT using ES2015/ES6 and I don't want to use Babel or other transpilers) and I have one that inherits from the other, overriding one of the parent methods.
So I have my initial App.Hello
class:
var App = {};
App.Hello = function(args) {
this.name = args.name;
}
App.Hello.prototype = {
constructor: App.Hello,
sayHello: function() {
console.log('Hello, ' + this.name);
},
sayGoodbye: function() {
console.log('Goodbye, ', this.name);
}
}
An then my App.Yo
class which inherits from it:
// inherits from App.Hello
App.Yo = function(args) {
App.Hello.call(this, args);
}
App.Yo.prototype = Object.create(App.Hello.prototype);
App.Yo.prototype = { // want to combine this with above!
constructor: App.Yo,
sayHello: function() {
console.log('Yo, ', this.name);
}
}
However because I'm using Object literal structure I overwrite the prototype of App.Yo
when I pass it the constructor
and sayHello
methods after setting the Object.create
. So I don't inherit the sayGoodby method from App.Hello
1. How can I get around this but using literal structure?
I know I could just do:
App.Yo.prototype = Object.create(App.Hello.prototype);
App.Yo.prototype.constructor = App.Yo;
App.Yo.prototype.sayHello = function sayHello() {
console.log('Yo, ', this.name);
}
But I want to keep the literal structure as my classes are going to have a lot of different methods in them. So want to keep it nice and tidy.
2. Is it possible to nest the complete class as a literal? So have the constructors as well nested as part of a literal?
e.g.
App.Hello = function(args) {
this.name = args.name;
}
and
App.Yo = function(args) {
App.Hello.call(this, args);
}
Upvotes: 1
Views: 69
Reputation: 1074335
- How can I get around this but using literal structure?
Use Object.assign
, which was added in ES2015 but which can be polyfilled so you don't have to transpile:
App.Yo.prototype = Object.assign(Object.create(App.Hello.prototype), {
constructor: App.Yo,
sayHello: function() {
console.log('Yo, ', this.name);
}
});
Or if you don't want to polyfill, just use your own helper, like the standard extend
function (jQuery has one called $.extend
, as do many other utility libraries):
function extend(target) {
var i, source;
for (i = 1; i < arguments.length; ++i) {
source = arguments[i];
Object.keys(source).forEach(function(name) {
target[name] = source[name];
});
}
return target;
}
App.Yo.prototype = extend(Object.create(App.Hello.prototype), {
constructor: App.Yo,
sayHello: function() {
console.log('Yo, ', this.name);
}
});
- Is it possible to nest the complete class as a literal?
Yes, by going further with helper functions. For instance:
function derive(base, props) {
var cls = function() {
return base.apply(this, arguments);
};
cls.prototype = Object.create(base.prototype);
Object.assign(cls.prototype, props); // Or use your `extend` here
return cls;
}
App.Yo = derive(App.Hello, {
constructor: App.Yo,
sayHello: function() {
console.log('Yo, ', this.name);
}
});
Of course, there are a lot of features missing from that, like controlling which arguments you use in Yo
vs. passing on to Hello
.
If you want to explore this further, you can look at my Lineage
library, which makes creating classes in ES5 and earlier fairly simple and declarative. Personally, I consider it obsolete because of ES2015 and transpiling, but you've said you don't want to use a transpiler...
Upvotes: 1