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
Related
I have read every article and example on the first page of Google and I still am having a hard to completely understanding how to properly implement Prototypal Inheritance in JavaScript. The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
First I will start with what I want to achieve if this was C#:
C#
class Base {
public string UI { get; set; } // Using a string just for simplicity
}
class Book : Base {
public Book(string title) {
this.title = title;
}
private string title { get; set; } // Title of book
}
Then I can instantiate a Book and be able to access UI on each instance:
var myBook = new Book("East of Eden");
myBook.UI = "some string"; // This work.. all Book instances have THEIR OWN UI string
JavaScript
Now lets say I have a base object in JS that I want all other objects to inherit from:
function Base() {
this.UI = {}
}
I then want another object type to inherit this model like this:
function Book(title){
this.title = title;
}
Book.prototype = new Base();
// Sometimes I have seen this line instead... nothing seems to work at all when I use this though, so I don't understand whats happening here
//Book.prototype = Object.create(Base.prototype);
Book.prototype.constructor = Book;
Book.prototype.getTitle = function(){
return this.title;
}
var myBook = new Book("East of Eden");
var anotherBook = new Book("Grapes of Wrath");
console.log(myBook.getTitle()); // East of Eden
myBook.UI.isRead = true;
console.log(myBook.UI);
console.log(anotherBook.getTitle()); // Grapes of Wrath
anotherBook.UI.isHardcopy = true;
myBook.UI.isRead = false;
console.log(anotherBook.UI); // This UI object has isRead on it as well!!! NOOOO
So this doesn't really work because both instances are sharing the same UI object, but what I want is for them to have their OWN instance of the UI object.
Another method I have seen is to not use the 'new' keyword at all and only use Object.create() to get new objects. However, I am not sure how I would implement my Base class with some subclass like Book and then create multiple instances of Book, each with their own UI properties.
Could someone please give me an example of how to inherit a base class and create instances of that subclass with their own UI objects? Thanks
EDIT
So would the "simple" way of achieve what I want just be to do something like:
var Base = {
UI: {}
}
function Book(title){
_.extend(this, Base);
this.title = title;
}
var myBook = new Book("East of Eden");
myBook.UI.prop = 5; // This works now but doesn't utilize true inheritance at all!
Prototypes are linked and not copied. This means that when you did:
function Base(){
this.UI = {}
}
Book.prototype = new Base();
Book.prototype.constructor = Book;
The prototype of your Book constructor will be a new instance of Base. All your instances of Book will have the same prototype, the same instance of Base. Since it's this object which holds the UI property, all Book instances will fallback to the same object property.
Think that your Prototype will be:
var proto = {
UI : { }
}
All your Book instances will have access to this object:
var a = new Book('East of Eden');
var b = new Book('Grapes of Wrath');
a.UI.prop = 'prop'; //proto.UI.prop === 'prop'
b.UI.prop === 'prop'; //because it's also proto.UI.prop
If you actually define a property on Book instances, say on its constructor:
function Book(title){
this.title = title;
this.UI = { };
}
You'll see that they are different objects:
a.UI !== b.UI //true
a.UI.prop = 'prop';
b.UI.prop !== b.UI; //true
Calling the constructor is the most obvious way to also initialize the properties on their children:
function Book(title){
Base.call(this);
this.title = title;
}
Regarding the difference between new Base() and Object.create(Base.prototype).
new Base() will initialize the object and call the constructor, while Object.create(Base.prototype) will do basically the same, except it won't call the constructor. This means, that the prototype won't have the properties set on the constructor (UI).
The biggest challenge I'm facing is I am seeing many different ways to implement the inheritance.
There really is only one correct way.
Use Object.create to establish inheritance:
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
configurable: true,
}
});
Then apply the parent constructor in the child constructor to the child instance:
function Child() {
Parent.call(this);
}
This is basically what happens under the hood if you'd use ES2015's new class syntax.
See Benefits of using `Object.create` for inheritance for more details on Object.create and why you want to use it in this case.
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');
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();
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use of ‘prototype’ vs. ‘this’ in Javascript?
Object Oriented questions in Javascript
Can you please recommend which of the following is the best or their pros and cons?
Method 1
function User() {
this.name = "my name";
this.save = function() {
};
}
Method 2
function User() {
this.name = "my name";
}
User.prototype.save = function() {
}
Coming from a background in Java and PHP, I had initially struggled with the whole 'class' concept in JavaScript. Here are a few things to think about.
Construction
First, since you're likely going to be defining your classes as..
Customer = function () {}
Customer.prototype = new Person();
You will end up running into all sorts of nightmares of code if you are defining properties and methods during construction. The reason being is that a piece of code like Customer.prototype = new Person(); requires that the Person be called in the Customer constructor for true inheritance.. otherwise you'll end up having to know what the original one sets at all times. Take the following example:
Person = function (name) {
this.name = name;
this.getName = function () {return this.name}
}
Customer = function (name) {
this.name = name;
}
Customer.prototype = new Person();
Now we're going to update Person to also set whether they are 'new':
Person = function (name, isNew) {
this.name = name;
this.isNew = isNew;
this.getName = function () {return (this.isNew ? "New " : "") + this.name; }
}
Now on any 'class' that is inheriting from the Person, you must update the constructor to follow form. You can get around that by doing something like:
Customer = function () {
Person.apply(this, arguments);
}
That will call 'Person' in the scope of the new 'Customer', allowing you to not have to know about the Person construction.
Speed
Take a look at these benchmarks: http://jsperf.com/inherited-vs-assigned.
Basically, what I am attempting to prove here is that if you're creating these objects en masse, your best route is to create them on the prototype. Creating them like:
Person = function (name) {
this.name = name;
this.getName = function () {return this.name}
}
is very slow, because for every object creation, it creates a new function - it doesn't simply look up the prototype chain for the already existing one. Conversely, if you've got only a few objects that the methods are called extremely frequently on, defining them locally helps with the speed lost by looking up the prototype chain.
Shared properties
This always gets me. Let's say you've got something like the following:
Person = function () {
this.jobs = {};
this.setJob = function (jobTitle, active) {this.jobs[jobTitle] = active; }
}
Employee = function () {}
Employee.prototype = new Person();
var bob = new Employee();
bob.setJob('janitor', true);
var jane = new Employee();
console.log(jane.jobs);
Guess what? Jane's a janitor! No joke! Here's why. Since you didn't define this.jobs as being a new object on instantiation of the Employee, it's now just looking up the prototype chain until it finds 'jobs' and is using it as is. Fun, right?
So, this is useful if you want to keep track of instances, but for the most part you're going to find it incredibly frustrating. You can get around that by doing the following:
Employee = function () { Person.apply(this); }
This forces 'Person' to create a new 'this.jobs'.
Private variables
Since there's nothing that's really "private" in JavaScript, the only way you can get private variables is to create them in the constructor, and then make anything that relies on them initialize in the constructor.
Person = function () {
var jobs = {};
this.setJob = function (jobTitle, active) {jobs[jobTitle] = active; }
this.getJob = function (jobTitle) { return jobs[jobTitle]; }
}
However, this also means that you must call that constructor on every instantiation of an inherited class.
Suggestion
http://ejohn.org/blog/simple-javascript-inheritance/
This is a super basic class setup. It's easy. It works. And it'll do what you need it to do 90% of the time without having to deal with all the insanity JavaScript has to offer :)
</rant>
Best is a very subjective term.
Method 1 gives the possibility of truly private variables. e.g :
function User() {
var name = "fred";
this.getName = function () { return name;};
}
Method 2 will use less memory, as a single save function is shared by all User objects.
'Best' will be determined by your specific requirements.
JavaScript is an "Object Based" language, not a "Class Based" language. Shared behaviours, which is the class concept, are implemented by linking prototypes.
Method 1 does NOT create a class. Every time you invoke it, you create attributes and functions as defined and they are NOT shared with other "instances". If you replace this.save then only the one instance will have altered behaviour.
Method 2 implements shared behaviours. Therefore it is what people associate with classes and instances. If you replace this.save withe a different function, then all derived instances will immediately have the new behaviour.
If "best" means no memory consuming redefinitions of functions and sharing common behaviours (which is what class based programming tends to equate to) the Method 2 is the way to go.
As others have mentioned, there are two main differences:
Method 1 will create a new function for every instance of User
Method 1 will be able to access local variables in the constructor's scope
Here's an example to demonstrate these:
function User() {
var name = "my name";
this.foo = function() {
// one function per User instance
// can access 'name' variable
};
}
User.prototype.bar = function() {
// one function shared by all User instances
// cannot access 'name' variable
};
var a = new User();
var b = new User();
console.log(a.foo === b.foo); // false; each instance has its own foo()
console.log(a.bar === b.bar); // true; both instances use the same bar()
Quite recently I read about JavaScript call usage in MDC
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call
one linke of the example shown below, I still don't understand.
Why are they using inheritance here like this
Prod_dept.prototype = new Product();
is this necessary? Because there is a call to the super-constructor in
Prod_dept()
anyway, like this
Product.call
is this just out of common behaviour? When is it better to use call for the super-constructor or use the prototype chain?
function Product(name, value){
this.name = name;
if(value >= 1000)
this.value = 999;
else
this.value = value;
}
function Prod_dept(name, value, dept){
this.dept = dept;
Product.call(this, name, value);
}
Prod_dept.prototype = new Product();
// since 5 is less than 1000, value is set
cheese = new Prod_dept("feta", 5, "food");
// since 5000 is above 1000, value will be 999
car = new Prod_dept("honda", 5000, "auto");
Thanks for making things clearer
The answer to the real question is that you need to do both:
Setting the prototype to an instance of the parent initializes the prototype chain (inheritance), this is done only once (since the prototype object is shared).
Calling the parent's constructor initializes the object itself, this is done with every instantiation (you can pass different parameters each time you construct it).
Therefore, you should not call the parent's constructor when setting up inheritance. Only when instantiating an object that inherits from another.
Chris Morgan's answer is almost complete, missing a small detail (constructor property). Let me suggest a method to setup inheritance.
function extend(base, sub) {
// Avoid instantiating the base class just to setup inheritance
// Also, do a recursive merge of two prototypes, so we don't overwrite
// the existing prototype, but still maintain the inheritance chain
// Thanks to #ccnokes
var origProto = sub.prototype;
sub.prototype = Object.create(base.prototype);
for (var key in origProto) {
sub.prototype[key] = origProto[key];
}
// The constructor property was set wrong, let's fix it
Object.defineProperty(sub.prototype, 'constructor', {
enumerable: false,
value: sub
});
}
// Let's try this
function Animal(name) {
this.name = name;
}
Animal.prototype = {
sayMyName: function() {
console.log(this.getWordsToSay() + " " + this.name);
},
getWordsToSay: function() {
// Abstract
}
}
function Dog(name) {
// Call the parent's constructor
Animal.call(this, name);
}
Dog.prototype = {
getWordsToSay: function(){
return "Ruff Ruff";
}
}
// Setup the prototype chain the right way
extend(Animal, Dog);
// Here is where the Dog (and Animal) constructors are called
var dog = new Dog("Lassie");
dog.sayMyName(); // Outputs Ruff Ruff Lassie
console.log(dog instanceof Animal); // true
console.log(dog.constructor); // Dog
See my blog post for even further syntactic sugar when creating classes. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Technique copied from Ext-JS and http://www.uselesspickles.com/class_library/ and a comment from https://stackoverflow.com/users/1397311/ccnokes
The ideal way to do it is to not do Prod_dept.prototype = new Product();, because this calls the Product constructor. So the ideal way is to clone it except for the constructor, something like this:
function Product(...) {
...
}
var tmp = function(){};
tmp.prototype = Product.prototype;
function Prod_dept(...) {
Product.call(this, ...);
}
Prod_dept.prototype = new tmp();
Prod_dept.prototype.constructor = Prod_dept;
Then the super constructor is called at construction time, which is what you want, because then you can pass the parameters, too.
If you look at things like the Google Closure Library you'll see that's how they do it.
If you have done Object Oriented Programming in JavaScript, you will know that you can create a class as follows:
Person = function(id, name, age){
this.id = id;
this.name = name;
this.age = age;
alert('A new person has been accepted');
}
So far our class person only has two properties and we are going to give it some methods. A clean way of doing this is
to use its 'prototype' object.
Starting from JavaScript 1.1, the prototype object was introduced in JavaScript. This is a built in object that
simplifies the process of adding custom properties and methods to all instances of an object.
Let's add 2 methods to our class using its 'prototype' object as follows:
Person.prototype = {
/** wake person up */
wake_up: function() {
alert('I am awake');
},
/** retrieve person's age */
get_age: function() {
return this.age;
}
}
Now we have defined our class Person. What if we wanted to define another class called Manager which inherits some properties from Person. There is no point redefining all this properties again when we define our Manager class, we can just set it to inherit from the class Person.
JavaScript doesn't have built in inheritance but we can use a technique to implement inheritance as follows:
Inheritance_Manager = {};//We create an inheritance manager class (the name is arbitrary)
Now let's give our inheritance class a method called extend which takes the baseClass and subClassas arguments.
Within the extend method, we will create an inner class called inheritance function inheritance() { }. The reason why we are using this inner
class is to avoid confusion between the baseClass and subClass prototypes.
Next we make the prototype of our inheritance class point to the baseClass prototype as with the following code:
inheritance.prototype = baseClass. prototype;
Then we copy the inheritance prototype into the subClass prototype as follows: subClass.prototype = new inheritance();
The next thing is to specify the constructor for our subClass as follows: subClass.prototype.constructor = subClass;
Once finished with our subClass prototyping, we can specify the next two lines of code to set some base class pointers.
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
Here is the full code for our extend function:
Inheritance_Manager.extend = function(subClass, baseClass) {
function inheritance() { }
inheritance.prototype = baseClass.prototype;
subClass.prototype = new inheritance();
subClass.prototype.constructor = subClass;
subClass.baseConstructor = baseClass;
subClass.superClass = baseClass.prototype;
}
Now that we have implemented our inheritance, we can start using it to extend our classes. In this case we are going to
extend our Person class into a Manager class as follows:
We define the Manager class
Manager = function(id, name, age, salary) {
Person.baseConstructor.call(this, id, name, age);
this.salary = salary;
alert('A manager has been registered.');
}
we make it inherit form Person
Inheritance_Manager.extend(Manager, Person);
If you noticed, we have just called the extend method of our Inheritance_Manager class and passed the subClass Manager in our case and then the baseClass Person. Note that the order is very important here. If you swap them, the inheritance
will not work as you intended if at all.
Also note that you will need to specify this inheritance before you can actually define our subClass.
Now let us define our subClass:
We can add more methods as the one below. Our Manager class will always have the methods and properties defined in the Person class because it inherits from it.
Manager.prototype.lead = function(){
alert('I am a good leader');
}
Now to test it let us create two objects, one from the class Person and one from the inherited class Manager:
var p = new Person(1, 'Joe Tester', 26);
var pm = new Manager(1, 'Joe Tester', 26, '20.000');
Feel free to get full code and more comments at:
http://www.cyberminds.co.uk/blog/articles/how-to-implement-javascript-inheritance.aspx