JavaScript - how to make it possible to inherit - javascript

I'm trying to make it possible to inherit from this class:
function Vehicle(p) {
this.brand = p.brand || "";
this.model = p.model || "";
this.wheels = p.wheels || 0;
}
Vehicle.prototype.getBrand = function () {
return this.brand;
};
Vehicle.prototype.getModel = function () {
return this.model;
};
Vehicle.prototype.getWheels = function () {
return this.wheels;
};
var myVehicle = new Vehicle({
brand: "Mazda",
model: "RX7",
wheels: 4
});
console.log(myVehicle);
I tried doing it this way:
function Vehicle(p) {
this.brand = p.brand || "";
this.model = p.model || "";
this.wheels = p.wheels || 0;
}
Vehicle.prototype.getBrand = function () {
return this.brand;
};
Vehicle.prototype.getModel = function () {
return this.model;
};
Vehicle.prototype.getWheels = function () {
return this.wheels;
};
function Car (){}
Car.prototype = new Vehicle();
Car.prototype.getWheels = function() {
return 4;
};
var myCar = new Car({
brand: "Mazda",
model: "RX7"
});
console.log(myCar);
but it seems like it doesn't work:
> Uncaught TypeError: Cannot read property 'brand' of undefined
Could someone explain to me what's wrong? I guess it's not the write way to implement it but why?

In addition to what #elclanrs said:
function Car () {
Vehicle.apply(this, arguments);
}
var c = function() {};
c.prototype = Vehicle.prototype;
Car.prototype = new c();
Live demo: http://jsfiddle.net/x3K9b/1/

You need to call "super" in Car:
function Car() {
Vehicle.apply(this, arguments);
}
Aside from that you could make p optional by just assigning an empty object for example; that would get rid of the error. And finally point to the right constructor so:
function Vehicle(p) {
p = p || {}; //<=
this.brand = p.brand || "";
this.model = p.model || "";
this.wheels = p.wheels || 0;
}
//...
Car.prototype = new Vehicle();
Car.prototype.constructor = Car; //<=
Edit: Otherwise just use Object.create:
Car.prototype = Object.create(Vehicle.prototype);
That takes care of assigning the constructor and everything.

Related

Aliasing or otherwise merging two identical object prototypes with different names

I've got two object prototypes like this:
function Tag(name, description) {
this.name = name;
this.description = description || null;
}
function Category(name, description) {
this.name = name;
this.description = description || null;
}
Both of them are exactly the same, which seems awkward. Is it possible to merge them both into an object named 'Entity', and refer to them both by different names (the original 'Tag' and 'Category')?
This may be further complicated by the fact I need to refer to the current prototype name inside the prototype.
Tag.prototype.toJSON = function() {
return {
__type: 'Tag',
name: this.name,
description: this.description
};
};
How can I apply the same 'toJSON' extension to the 'Entity' object, but make sure it returns 'Tag' or 'Category' in the '__type' field, dependent on which object is being used?
I would do something like this:
Dummy = function () {};
Entity = function (name) {
this.name = name;
};
Entity.prototype.toString = function () {
return "My name is " + this.name + ".";
};
A = function () {
Entity.call(this, 'A');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = A;
A.prototype = new Dummy();
B = function () {
Entity.call(this, 'B');
};
Dummy.prototype = Entity.prototype;
Dummy.prototype.constructor = B;
B.prototype = new Dummy();
document.body.innerHTML = ""
+ (new A()) + "<br />"
+ (new B());
Here is a small function to make things cleaner (hopefully):
function Nothing () {};
function extend (Sup, proto) {
function Class () {
if (this.init) {
this.init.apply(this, arguments);
}
}
Nothing.prototype = Sup.prototype;
Nothing.prototype.constructor = Sup;
Class.prototype = new Nothing();
delete Nothing.prototype;
for (var k in proto) {
Class.prototype[k] = proto[k];
}
return Class;
}
Here is how to use it:
Entity = extend(Nothing, {
init: function (name) {
this.name = name;
},
toString: function () {
return "My name is " + this.name + ".";
}
});
A = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'A');
}
});
B = extend(Entity, {
init: function () {
var sup = Entity.prototype;
sup.init.call(this, 'B');
}
});

accessing static (class) variables defined in a subclass from a superclass

I have some classes that share identical methods and are distinguished only by a few static (aka class) variables. My thought is to put the common methods into a base class that accesses the static variables.
Here is a solution that works, but it seems like a real cough kludge. Is there a better / more idiomatic way to do this?
"use strict";
// common code
function Base() { }
Base.prototype.f1 = function() {
console.log(Object.getPrototypeOf(this).constructor.VAR1); // this feels really really wrong!
}
Base.prototype.f2 = function() {
console.log(Object.getPrototypeOf(this).constructor.VAR2); // ditto
}
// specialization A
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.VAR1 = "suba v1";
SubA.VAR2 = "suba v2";
// specialization B
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.VAR1 = "subb v1";
SubB.VAR2 = "subb v2";
This works as expected:
> var a = new SubA();
> var b = new SubB();
> a.f1()
suba v1
undefined
> b.f2()
subb v2
undefined
an alternative
Of course I could write methods to encapsulate the differences between SubA and SubB. The syntax is less tortured, but it still feels wrong to write methods that are essentially behaving like static variables:
"use strict";
function Base() { }
Base.prototype.f1 = function() {
console.log(this.getVar1());
}
Base.prototype.f2 = function() {
console.log(this.getVar2());
}
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.prototype.getVar1 = function() { return 'suba v1'; }
SubA.prototype.getVar2 = function() { return 'suba v2'; }
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.prototype.getVar1 = function() { return 'subb v1'; }
SubB.prototype.getVar2 = function() { return 'subb v2'; }
> var a = new SubA();
> var b = new SubB();
> a.f1()
suba v1
undefined
> b.f2()
subb v2
undefined
Is there a particular reason to put VAR1 and VAR2 in the class objects themselves rather than in their prototypes? If not, things become much simpler:
function Base() { }
Base.prototype.f1 = function() {
console.log(this.VAR1);
};
Base.prototype.f2 = function() {
console.log(this.VAR2);
};
// specialization A
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.prototype.VAR1 = "suba v1";
SubA.prototype.VAR2 = "suba v2";
// specialization B
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.prototype.VAR1 = "subb v1";
SubB.prototype.VAR2 = "subb v2";
The above code passes your tests.

Javascript Object-Oriented-Programming

I found a Module pattern in JS:
<script>
var MODULENAME = (function(my, $) {
my.publicVar = "5";
my.publicFn = function() {};
return my;
}(MODULENAME || {}, jQuery));
</script>
However I cannot perform instantiation. Does the module pattern allow for that?
Instantiantion means basically that you'll run a function using new.
So maybe you're looking for this?
var Some = function (param) {
var somePrivateVar = 'private';
this.somePublicVar = 'public';
this.method = function () {
return param;
};
};
var some = new Some('abla');
console.log(some.method());
// some.somePrivateVar === undefined
// some.somePublicVar === 'public'
In your case MODULENAME is an object (object, not a function) with publicVar and publicFn. It's not meant to be instantiated the same way you wouldn't call new jQuery().
Your module object can contain anything. Perhaps you're looking for including a constructor in it:
var MODULENAME = (function(my, $) {
var privateVar = 10;
my.SomeConstructor = function() {
this.publicVar = 5;
}
my.SomeConstructor.prototype.someMethod = function() {};
my.SomeConstructor.prototype.getPrivate = function() { return 10; };
return my;
}(MODULENAME || {}, jQuery));
var instance = new MODULENAME.SomeConstructor();
instance.publicVar; // 5
instance.privateVar; // undefined
instance.getPrivate(); // 10
You can do this also with prototype Inheritance :
var MyClass = function(name)
{
//sharing name within the whole class
this.name = name;
}
MyClass.prototype.getName = function(){
return this.name;//now name is visible to getName method too
}
MyClass.StaticMethod = function()
{
console.log("Im Static");
// and since is not in prototype chain, this.name is not visible
}
var myclass = new MyClass("Carlos");
console.log(myclass.getName())//print "Carlos"
MyClass.StaticMethod()// print "Im Static"
myclass.StaticMethod() // error
Se all this article

JavaScript prototype extending

I'm trying to extend an Abstract object.
var Abstract = function() { code = 'Abstract'; };
Abstract.prototype.getCode = function() { return code; };
Abstract.prototype.getC = function() { return c; };
var ItemA = function() { code = 'ItemA'; c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
var b = new ItemB();
console.log(b.getCode());
var a = new ItemA();
console.log(b.getCode());
console.log(b.getC());
The result:
ItemB
ItemA
a
Is there any particular reason why I'm getting ItemA's scope in ItemB instance? How can I fix it?
It is because you are using global variables. Fix it by using this keyword:
var Abstract = function() { this.code = 'Abstract'; };
Abstract.prototype.getCode = function() { return this.code; };
Abstract.prototype.getC = function() { return this.c; };
var ItemA = function() { this.code = 'ItemA'; this.c = 'a'; };
ItemA.prototype = Object.create(Abstract.prototype);
ItemA.prototype.constructor = ItemA;
var ItemB = function() { this.code = 'ItemB'; };
ItemB.prototype = Object.create(Abstract.prototype);
ItemB.prototype.constructor = ItemB;
Although in this case ItemB.getC() will return undefined.

Prototypal Namespacing

I have a Constructor function "Animals", that is namespacing some other Constructor functions, "Crocodile" and "Monkey":
var Monkey = function(Animals) {
this.Animals = Animals;
};
Monkey.prototype.feedMe = function() {
this.Animals.feed();
};
var Crocodile = function(Animals) {
this.Animals = Animals;
};
Crocodile.prototype.feedMe = function() {
this.Animals.feed();
};
var Animals = function(zoo) {
this.zoo = zoo;
};
Animals.prototype.feed = function() {
//feed the animal
};
Animals.prototype.Monkey = function() {
this.Animals = Animals.prototype;
};
Animals.prototype.Monkey.prototype = Monkey.prototype;
Animals.prototype.Crocodile = function() {
this.Animals = Animals.prototype;
};
Animals.prototype.Crocodile.prototype = Crocodile.prototype;
With the intention that I should be able to do the following:
var animals = new Animals("NY");
var monkey = new animals.Monkey();
monkey.feed();
I'm receiving an error that says that monkey.feed() is not a function. I'm assuming i'm doing something wrong with the way i'm inheriting the Monkey function inside the Animal constructor function but for the life of me I haven't been able to find the solution.
What is the correct method I should be using to namespace these functions?
I have seen quite some stuff, but abusing prototypes for namespaces, what the heck. What's wrong with a nice and simple:
var Animals = {
Crocodile: {
}
}
Or if you want the constructor way:
var Animals = function () {
return {
Crocodile: function () {}
}
};
var a = new Animals();
var c = new a.Crocodile();

Categories