Inheriting class methods Javascript - javascript

Lets say I have two APIs and I would like to inherit classes from the first, but modify the response with .prototype.toJSON().
When I inherit from the first class, how can I inherit class methods as well.
An example
//file v1/models/users.js
var UserModel = function() {
this.id = 0;
this.firstName = '';
this.lastName = '';
}
UserModel.find = function(q, callback) {
//find any user that matches q and map them to UserModel
if (err) return callback(err, null);
callback(null, users);
}
module.exports = UserModel;
And the the next version
//file v2/models/users.js
var UserModel = require('../v1/models/users');
function UserModelV2() {
UserModel.call(this);
}
UserModelV2 = Object.create(UserModel.prototype);
UserModelV2.prototype.constructor = UserModel;
UserModelV2.prototype.toJSON = function() {
var obj = {};
obj.firstName = 'foo';
return obj;
}
module.exports = UserModelV2;
When I now try to call
var User = require('./v2/models/users');
User.find(1);
I get an error saying User.find does not exists.
I am aware I am only inheriting prototypal properties, but I cannot find an example of inheriting class methods anywhere.

Don't add find directly onto UserModel because that causes the method to be added only to one instance.
Add it to the prototype:
UserModel.prototype.find = function(id) {
//find the user by id and return
}
Because all instances of UserModel will inherit from the prototype of your constructor function.
Then, your next version would inherit from the first like this:
// Constructor of sub-class
function UserModelV2() {
// Call the prototype.constructor, not just .constructor
UserModel.prototype.constructor.call(this);
}
// Perform inheritance
UserModelV2.prototype = new UserModel();
// Correct the constructor of the prototype
UserModelV2.prototype.constructor = UserModelV2;
// Extend the sub-class
UserModelV2.prototype.toJSON = function() {
var obj = {};
obj.firstName = 'foo';
return obj;
}
By the way (and this could be why you got stuck on this), technically (and despite the class keyword), JavaScript does not have classes, it has prototypes and they are the basis for inheritance.

Well, you can simply copy the methods over from UserModel
Object.assign(UserModelV2, UserModel);
Or you define that the UserModelV2 function inherits its properties from the UserModel function instead of Function.prototype directly.
Object.setPrototypeOf(UserModelV2, UserModel);
Or you use the new class syntax and let that take care of this:
class UserModelV2 extends UserModel {
toJSON(){
return {firstName: 'foo'};
}
}
maybe in combination with a transpiler like babel, if you need backwards compatibility.
I'd encourage the last option. To me this seems like the cleanest approach and provides you with the ability to not use the transpiler.
And it is semantically clear. Even the JS compiler can tell that you're not just arbitrarily messing around with the prototype of some function and may break something or do something "weird".

Related

reusable javascript objects, prototypes and scope

MyGlobalObject;
function TheFunctionICanUseRightAwaySingleForAllInstansesAndWithoutInstanse() {
function() {
alert('NO CONSTRUCTOR WAS CALLED');
}
};
The Long-named function must be callable from MyGlobalObject, which in turn must be available as a global (to window) variable in all times after script was loaded. It should support extensibility in accordance with latest standards.
I'm at architectural dilemma of how to built JS base for an application (almost 100% JS).
We need an object i.e. window.MyObject (like a module, like jQuery) so
It can be created with
VAR1
var MyGlobalObjConstructor = function(){
this.GlobalFunctionInObject = function(){
alert('called with MyGlobalObj.GlobalFunctionInObject()');
}
};
window.MyGlobalObj = new MyGlobalObjConstructor();
Is MyGlobalObj extensible? Can I create child objects, which will inherit current state of MyGlobalObj (extended functions/properties MyGlobalObj.NewFunc e.g.)? What is the main difference between using prototype (VAR3)?
By GlobaldFunction I mean single instance for all initialized/instantiated (possibly instantializable) instances..
Or with
VAR2
var MyGlobalObj = {
GlobalFunctionInObject: function...
GlobalFunctionInObject2: function...
};
MyGlobalObj.GlobalFunctionInObject();
// here I lose all hierarchy elements, no prototype,
// can I use GlobalFunctionInObject2 in GlobalFunctionInObject?
Or with
VAR3
var MyGlobalConstuctor = function(){} // already 'well-formed' object
MyGlobalConstuctor.prototype.GlobalFunctionInObject = function...
};
var MyGlobalObj = new MyGlobalConstuctor();
// so I'm sceptical to NEW, because I have ALREADY wrote my functions
// which I expect to be in memory, single instance of each of them,
// so creating MyObject2,3,4 with NEW MyGC() makes no sense to me.
// DO I REALLY HAVE TO USE "MyGlobalConstuctor.prototype." FOR EACH FUNCTION?!!!!
What's the difference defining MyGlobalObj as a function and as an object (result of func or VAR2)?
OR VAR4?
I see in Chrome Debugger both prototype and __proto__ special fields. I've read that that's OK, but why are they not saved in a single prototype?
So, what is the correct/optimal way to implement window.MyObject, so one could MyObject.MyFunction(); What are the differences (pro/contra) of variants 1 2 and 3?
Variation 1 - Mixin
function SomeType() {
var priv = "I'm private";
this.publ = "I'm public";
this.action = function() {
return priv + this.publ;
};
}
var obj = new SomeType();
With this method you are creating a new object every time you call new SomeType(), creating all its methods and adding all this method to the new object. Every time you create an object.
Pros
It looks like classical inheritance so it's easy to understand to Java-C#-C++-etc people.
It can have private variables per instance since you have one function closure per each object you create
It allows multiple inheritance, also known as Twitter-mixins or functional mixins
obj instanceof SomeType will return true
Cons
It consumes more memory as more objects you create because with each object you are creating a new closure and creating each of it's methods again.
Private properties are private, not protected, subtypes can't access them
No easy way to know if a object has some Type as superclass.
Inheritance
function SubType() {
SomeType.call(this);
this.newMethod = function() {
// can't access priv
return this.publ;
};
}
var child = new SubType();
child instanceof SomeType will return false there is no other way to know if child has SomeType methods than look if it has them one by one.
Variation 2 - Object literal with prototyping
var obj = {
publ: "I'm public",
_convention: "I'm public too, but please don't touch me!",
someMethod: function() {
return this.publ + this._convention;
}
};
In this case you are creating a single object. If you are going to need only one instance of this type it can be the best solution.
Pros
It's quick and easy to understand.
Performant
Cons
No privacy, every property is public.
Inheritance
You can inherit a object prototyping it.
var child = Object.create(obj);
child.otherMethod = function() {
return this._convention + this.publ;
};
If you are on a old browser you will need to garantee Object.create works:
if (!Object.create) {
Object.create = function(obj) {
function tmp() { }
tmp.prototype = obj;
return new tmp;
};
}
To know if a object is a prototype of another you can use
obj.isPrototypeOf(child); // true
Variation 3 - Constructor pattern
UPDATE: This is the pattern ES6 classes are sugar syntax of. If you use ES6 classes you are following this pattern under the hood.
class SomeType {
constructor() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
someMethod() {
return this.publ + this._convention;
}
}
class SubType extends SomeType {
constructor() {
super(/* parent constructor parameters here */);
this.otherValue = 'Hi';
}
otherMethod() {
return this._convention + this.publ + this.otherValue;
}
}
function SomeType() {
// REALLY important to declare every non-function property here
this.publ = "I'm public";
this._convention = "I'm public too, but please don't touch me!";
}
SomeType.prototype.someMethod = function() {
return this.publ + this._convention;
};
var obj = new SomeType();
You can re-assign the prototype insteadd of adding each method if you are not inheriting and remember to re-assign the constructor property:
SomeType.prototype = {
constructor: SomeType,
someMethod = function() {
return this.publ + this._convention;
}
};
Or use _.extend or $.extend if you have underscore or jquery in your page
_.extend(SomeType.prototype, {
someMethod = function() {
return this.publ + this._convention;
}
};
The new keyword under the hood simply does this:
function doNew(Constructor) {
var instance = Object.create(Constructor.prototype);
instance.constructor();
return instance;
}
var obj = doNew(SomeType);
What you have is a function than has no methods; it just has a prototype property with a list of functions, the new operator means to create a new object and use this function's prototype (Object.create) and constructor property as initializer.
Pros
Performant
Prototype chain will allow you to know if a object inherits from some type
Cons
Two-step inheritance
Inheritance
function SubType() {
// Step 1, exactly as Variation 1
// This inherits the non-function properties
SomeType.call(this);
this.otherValue = 'Hi';
}
// Step 2, this inherits the methods
SubType.prototype = Object.create(SomeType.prototype);
SubType.prototype.otherMethod = function() {
return this._convention + this.publ + this.otherValue;
};
var child = new SubType();
You may think it looks like a super-set of Variation 2... and you'll be right. It's like variation 2 but with a initializer function (the constructor);
child instanceof SubType and child instanceof SomeType will return both true
Curiosity: Under the hood instanceof operator does is
function isInstanceOf(obj, Type) {
return Type.prototype.isPrototypeOf(obj);
}
Variation 4 - Overwrite __proto__
When you do Object.create(obj) under the hood it does
function fakeCreate(obj) {
var child = {};
child.__proto__ = obj;
return child;
}
var child = fakeCreate(obj);
The __proto__ property modifies directly the object's hidden [Prototype] property. As this can break JavaScript behaviour, it's not standard. And the standard way is preferred (Object.create).
Pros
Quick and performant
Cons
Non-standard
Dangerous; you can't have a hashmap since the __proto__ key can change the object's prototype
Inheritance
var child = { __proto__: obj };
obj.isPrototypeOf(child); // true
Comment questions
1. var1: what happens in SomeType.call(this)? Is 'call' special function?
Oh, yes, functions are objects so they have methods, I will mention three: .call(), .apply() and .bind()
When you use .call() on a function, you can pass one extra argument, the context, the value of this inside the function, for example:
var obj = {
test: function(arg1, arg2) {
console.log(this);
console.log(arg1);
console.log(arg2);
}
};
// These two ways to invoke the function are equivalent
obj.test('hi', 'lol');
// If we call fn('hi', 'lol') it will receive "window" as "this" so we have to use call.
var fn = obj.test;
fn.call(obj, 'hi', 'lol');
So when we do SomeType.call(this) we are passing the object this to function SomeCall, as you remember this function will add methods to object this.
2. var3: With your "REALLY define properties" do you mean if I use them in functions? Is it a convention? Because getting this.newProperty without it being defined at the same level with other member functions is not a problem.
I mean any property your object will have that is not a function must be defined on the constructor, not on the prototype, otherwise you will face one of the more confusing JS problems. You can see it here, but it's outside of the focus of this question.
3. Var3: what happens if I don't re-assign constructor?
Actually you might not see the difference and this is what makes it a dangerous bug. Every function's prototype object has a constructor property so you can access the constructor from an instance.
function A() { }
// When you create a function automatically, JS does this:
// A.prototype = { constructor: A };
A.prototype.someMethod = function() {
console.log(this.constructor === A); // true
this.constructor.staticMethod();
return new this.constructor();
};
A.staticMethod = function() { };
It's not a best practice because not everybody knows about it, but sometimes it helps. But if you reassign the prototype...
A.prototype = {
someMethod = function() {
console.log(this.constructor === A); // false
console.log(this.constructor === Object); // true
this.constructor.staticMethod();
return new this.constructor();
}
};
A.prototype is a new object, a instance of Object than prototypes Object.prototype and Object.prototype.constructor is Object. Confusing, right? :P
So if you overwrite the prototype and don't reset the "constructor" property, it will refer to Object instead of A, and if you try to use the "constructor" property to access some static method you may get crazy.
I usually settle with returning an object with functions as properties:
var newCat = function (name) {
return {name: name, purr: function () {alert(name + ' purrs')}};
};
var myCat = newCat('Felix');
myCat.name; // 'Felix'
myCat.purr(); // alert fires
You can have inheritance by calling the newCat function and extend the object you get:
var newLion = function (name) {
var lion = newCat(name);
lion.roar = function () {
alert(name + ' roar loudly');
}
return lion;
}
If you want a global cats object:
var cats = (function () {
var newCat = function (name) {
return {
name: name,
purr: function () {
alert(name + ' is purring')
}
};
};
return {
newCat: newCat
};
}());
Now you can call:
var mySecondCat = cats.newCat('Alice');

Inheritance via a function?

I am learning the basics of OOP in Javascript and came across an inheritance example which is difference than what I've typically seen.
Typical:
ChildClass.prototype = new ParentClass();
Alternate Method:
function clone(object) {
function OneShotConstructor(){}
OneShotConstructor.prototype = object;
return new OneShotConstructor();
}
SecondClass.prototype = clone(FirstClass.prototype);
Why would the latter be preferred when creating an object whose prototype is another object?
Because you will invoke the constructor of the custom type (a.k.a. class) you are trying to inherit from. And that might have side effects. Imagine the following:
var instancesOfParentClass = 0;
function ParentClass (options) {
instancesOfParentClass++;
this.options = options;
}
function ChildClass () {}
ChildClass.prototype = new ParentClass();
Your counter has been incremented, but you didn't really create a useful instance of ParentClass.
Another problem, is that all instance properties (see this.options) will be present on ChildClass' prototype, and you probably don't want that.
Note: When using constructor, you might have instance properties, and shared properties. For example:
function Email (subject, body) {
// instance properties
this.subject = subject;
this.body = body;
}
Email.prototype.send = function () {
// do some AJAX to send email
};
// create instances of Email
emailBob = new Email("Sup? Bob", "Bob, you are awesome!");
emailJohn = new Email("Where's my money?", "John, you owe me one billion dollars!");
// each of the objects (instances of Email) has its own subject
emailBob.subject // "Sup? Bob"
emailJohn.subject // "Where's my money?"
// but the method `send` is shared across instances
emailBob.send === emailJohn.send // true

util.inherits - alternative or workaround

I am a n00b in node, and find util.inherits() very useful, except for the fact that it seems to replace the entire prototype of the original object. For instance:
var myClass = function(name){
this._name = name;
};
myClass.prototype = {
(...)
};
util.inherits(myClass, require('events').EventEmitter);
seems to erase my original prototype.
That brings me two inconveniences:
1 - I have to declare add properties to my prototype after calling inherits,
var myClass = function(name){
this._name = name;
};
util.inherits(myClass, require('events').EventEmitter);
myClass.prototype.prop1 = function(){...};
myClass.prototype.prop2 = function(){...};
and, most important, i think i cannot inherit from two or more different classes.
Can anyone explain to me why this makes sense and what would be a good way to work around this?
Thanks
It does not make sense that you have to declare your prototype after util.inherits(). My guess is util.inherits originated as an internal-use-only method, tailored only for the limited internal use-cases it was initially intended for, which at some point got published for general usage. The util module is written in pure JS, so it is very easy to implement your own version of util.inherit that preserves your prototype. Here's the original util.inherit source:
exports.inherits = function(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
As for the multiple inheritance, that's going to be a much more difficult problem to tackle, as Javascript's prototype inheritance is not really suited for multiple inheritance at all. Each instance has only a single internal [[Prototype]] property, which is used to look up members that are not found in the actual instance. You could merge the prototypes of two separate "parent classes" into a single prototype, but you will then lose the inheritance to their parents, and you will lose the ability to change the parent prototype and have all children see the change.
You should first inherit, after the function definition, and then implement your object. Also don't forget to call the superclass constructor in your class's constructor.
Function A(y){
this.y = x;
}
Function B(x,y){
this.x = x;
A.call(this,y);
}
util.inherits(B,A);
B.prototype.mythodA = function() {
//do something
}
As of node version 5.0.0, util.inherits has been changed to support the behaviour you are looking for using the setPrototypeOf method:
FirstBase.js
function FirstBase(firstBaseProp){
this.firstBaseProp = firstBaseProp;
}
FirstBase.prototype.getFirstBaseProp = function(){
return this.firstBaseProp;
};
module.exports = FirstBase;
SecondBase.js
var FirstBase = require('./FirstBase.js'),
util = require('util');
function SecondBase(firstBaseProp, secondBaseProp){
this.secondBaseProp = secondBaseProp;
SecondBase.super_.apply(this, arguments);
}
SecondBase.prototype.getSecondBaseProp = function(){
return this.secondBaseProp;
};
util.inherits(SecondBase, FirstBase);
module.exports = SecondBase;
ThirdBase.js
var SecondBase = require('./SecondBase.js'),
util = require('util');
function ThirdBase(firstBaseProp, secondBaseProp, thirdBaseProp){
this.thirdBaseProp = thirdBaseProp;
ThirdBase.super_.apply(this, arguments);
}
ThirdBase.prototype.getThirdBase = function(){
return this.thirdBaseProp;
};
util.inherits(ThirdBase, SecondBase);
module.exports = ThirdBase;
instance.js
var ThirdBase = require('./ThirdBase.js');
var instance = new ThirdBase('first', 'second', 'third');
// With node < 5.0.0 (Object.create)
console.log(instance.getFirstBaseProp()); // first
console.log(instance.getSecondBaseProp()); // undefined
console.log(instance.getThirdBase()); // undefined
// With node >= 5.0.0 (Object.setPrototypeOf)
console.log(instance.getFirstBaseProp()); // first
console.log(instance.getSecondBaseProp()); // second
console.log(instance.getThirdBase()); // third
If you're running an older version of node that supports setPrototypeOf (0.12.x does), you can just export util.inherits and use it as an internal utility function.
I very much wanted the same thing and was unhappy with extend, so I created this extension to the already useful util.inherits method:
var util = require('util');
module.exports = {
inherits : function(sub, sup, proto) {
util.inherits(sub, sup);
if (typeof proto !== 'undefined') {
Object.keys(proto).forEach(function(key) {
sub.prototype[key] = proto[key];
});
}
}
};
I put this in my project's ./util/index.js and then do this to use it:
var EventEmitter = require('events').EventEmitter;
var util = require('./util');
function Foo() {
EventEmitter.call(this);
}
util.inherits(Foo, EventEmitter, {
bar : function(){
console.log(this instanceof EventEmitter); // true
}
});
Maybe I'll publish this if I find it's robust and useful more and more. I just barely implemented it myself, so I'm giving it a test run.
Let me know what you think!
NOTE: This does override methods on either of the classes with the ones defined in the proto hash at the end. Just be aware of that.
Inherits-ex library is a browser-friendly enhanced inheritance fully compatible with standard node.js inherits with dynamic inheritance or creation.
static inheritance
multi-inheritances(inheritance chain) supports
inherits at anytime -- here is your wanted
you can not declare method/property before inherits in the standard way for it will replace the prototype object.
duplication inheritance check
Es6 Class supports
more helper functions
isInheritedFrom(ctor, superCtor|superCtorName) Check the ctor whether inherited from superCtor
mixin(ctor, superCtor|superCtor[]) Mixin the methods and properties of the SuperCtor: Clone(Copy) all superCtor's properties(methods) to ctor.
isMixinedFrom
createCtor
createObject
createFunction

Object Oriented JavaScript programming

I have been trying to learn OOP with JavaScript before I start attempting to learn backbone.js.
I want to be able to data bind but I can't seem to get it to work.
I've just made a simple protoype of a budget website that you can put in a budget and input how much you've spent, and it will show if you've gone over.
function BudgetItem(spent, budget){
this.setSpent = function(spent){
this.spent = spent;
}
this.setBudget = function(budget){
this.budget = budget;
}
this.getSpent = function(){
return this.spent;
}
this.getBudget = function(){
return this.budget;
}
}
function BudgetType(type){
this.getType = function(){
return type;
}
}
BudgetType.prototype = new BudgetItem();
$(document).ready(function(){
var food = new BudgetType('food');
$('.budget').html(food.getBudget());
$('.editbudget').change(function(){
food.setBudget($('.editbudget').data())
});
})
That's my code thus far. I'm not sure if I'm doing it right. Am I supposed to extend things? Also, can someone explain how to dynamically data bind without a library?
First I'll give you some theory. A Javascript function is a dynamic object, just like Object is, and a new instance can be created using the new keyword much like you are doing in your listener. When this happens, the function itself will run as a constructor while the this keyword will be bound to the newly created object. What you're doing above then is in fact adding new properties on the fly as you're passing in their values for the first time... which is fine, but not very clear to another reader.
Now for the tricky part. Every function has a link to a "hidden" Prototype object. This is an anonymous (not accessible by name) object created by the JavaScript runtime and passed as a reference to the user object through the prototype property. This Prototype object also has a reference to the function through its constructor property. To test what I'm saying for yourself, try the following:
BudgetItem.prototype.constructor === BudgetItem // true
Putting it all together, you can now think of functions as constructors to (hidden) classes that are created for you behind the scenes, accessible through the function's prototype property. So, you could add the fields to the Prototype object directly as so:
function BudgetItem(spent) {
this.spent = spent
}
BudgetItem.prototype.setSpent = function(spent) { this.spent = spent };
BudgetItem.prototype.getSpent = function() { return this.spent };
Another problem is inheritance and passing parameters to the constructor. Again, your version is valid but you lose the ability to pass the spent and budget values when initializing a BudgetType. What I would do is forget prototypes and go:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.type = type;
return instance;
}
This is close to what Scott Sauyet suggested above but more powerful. Now you can pass both parameters (and more) and have a more complicated inheritance tree.
Finally, what you can do is create private (or pseudo-private, more accurately) properties by providing a getter to an otherwise automatic variable (one passed as an argument or initialised inside the function). This is a special feature of the language and it works like so:
function BudgetType(type, spent) {
var instance = new BudgetItem(spent);
instance.getType = function() {
return type;
}
return instance;
}
Now you can access the 'type' passed in the constructor by obj.getType() but cannot override the initial value. Even if you define obj.type = 'New Value' the getType() will return the initial parameter passed because it has a reference to another context which was created when the object was initialised and never got released due to the closure.
Hope that helps...
if you want all instances of objects to reference the same members/values you can use a closure:
// create a constrctor for you object wrapped in a closure
myCon = (function() {
// define shared members up here
var mySharedObj = new function () {
this.member = "a";
}();
// return the actual constructor
return function () {
this.mySharedObj = mySharedObj;
}
}());
// create two instances of the object
var a = new myCon();
var b = new myCon();
// Altering the shared object from one
a.mySharedObj.member = "b";
// Alters it for all
console.log(b.mySharedObj.member);
If you want to build objects from other objects(sort of like other languages' class whatever extends baseClass), but do not want them to share values via reference(instead a clone of values), you can use something like the following:
Object.prototype.extendsUpon = (function (_prop, _args) {
return function (base) {
for (var key in base) {
if (_prop.call(base, key)) {
this[key] = base[key];
}
}
function con(child){
this.constructor = child;
}
con.prototype = base.prototype;
this.prototype = new con(this);
this.__base__ = base.prototype;
var args = _args.call(arguments);
args.shift();
base.constructor.apply(this, args);
}
}(Object.prototype.hasOwnProperty, Array.prototype.slice));
Then to build objects ontop of objects:
// Base Object Constructor
function Fruit(name) {
this.fruitname = name;
}
Fruit.prototype.yum = function() {
return "I had an " + this.fruitname;
}
// Object constructor that derives from the Base Object
function Favorite() {
// Derive this object from a specified base object:
// #arg0 -> Object Constructor to use as base
// #arg1+ -> arguments passed to the BaseObject's constructor
this.extendsUpon(Fruit, "apple");
// From here proceed as usual
// To access members from the base object that have been over-written,
// use "this.__base__.MEMBER.apply(this, arguments)"
}
Favorite.prototype.yum = function() {
return this.__base__.yum.apply(this) + " and it was my favorite";
}
var mmm = new Favorite();
// Outputs: "I had an apple and it was my favorite"
mmm.yum();

Copying Javascript getters/setters to another prototype object

// Base class
var Base = function() {
this._value = 'base';
};
Base.prototype = {
constructor: Base,
// By function
getValue: function() {
return this._value;
},
// By getter
get value() {
return this._value;
}
};
// Sub class extends Base
var Sub = function() {
this._value = 'sub';
};
Sub.prototype = {
constructor: Sub
};
// Pass over methods
Sub.prototype.getValue = Base.prototype.getValue;
Sub.prototype.value = Base.prototype.value;
// ---
var mySub = new Sub();
alert(mySub.getValue()); // Returns 'sub'
alert(mySub.value); // Returns 'undefined'
At first glance it seems that mySub.value should return the same as mySub.getValue(), but as you can see it instead returns undefined. Obviously the getter is not finding the parent scope as the Sub instance (mySub), but rather a non-existent Base instance.
Is there any way around this other than having to assign the same getters onto the new prototype?
A more modern solution is to use the Object.defineProperty since it allows getters and setters to be handled without breaking them.
Only problem is that it takes a descriptor object, so instead of manually making one, use the Object.getOwnPropertyDescriptor function to just get it for you.
var BazValue = Object.getOwnPropertyDescriptor(Base.prototype,'value');
Object.defineProperty(Sub.prototype, 'value', BazValue);
Sub.prototype.__defineGetter__('value', Base.prototype.__lookupGetter__('value'));
Try that.
I think it would work if you assigned
Sub.prototype = new Base()
The issue is that the constructor is never run when you assign it directly from the Base.prototype.value. That value won't exist until you have an instance of the Base class (via new)
This is my typical method for extending Function to achieve inheritance:
Function.prototype.Extend = function(superClass) {
this.prototype = new superClass();
this.prototype.getSuperClass = function() {
return superClass;
};
this.getSuperClass = this.prototype.getSuperClass;
return this;
};
This will properly assign all of the parent classes methods and properties to the child 'class'.
Usage looks like
var Sub = function() {}
Sub.Extend(Base)
In addition to Alex Mcp's answer you could add new getters/setters to Sub after extending it using:
Function.prototype.addGetter = function(val,fn){
this.prototype.__defineGetter__(val,fn);
return this;
}
Function.prototype.addSetter = function(val,fn){
this.prototype.__defineSetter__(val,fn);
return this;
}
//example;
Sub.Extend(Base);
Sub.addGetter('date',function(){return +new Date;});
And to add to tylermwashburns answer: you could extend the Function prototype for that:
Function.prototype.copyGetterFrom = function(val,fromConstructor){
this.prototype.__defineGetter__(
val
,fromConstructor.prototype.__lookupGetter__(val));
return this;
}
//usage example.:
Sub.copyGetterFrom('value',Base);

Categories

Resources