-1

I have a question in regards to classical inheritance vs prototypical inheritance. I wanted to see what is better?

Let's say we have a function called familyTree.

function familyTree(){
  this.lastname = "xyz";
}

If i want to add any additional details for them as far as I read, we can inherit parent in two ways:

1: prototypical way:

familyTree.prototype.personDetails = function(){

this.firstName = "abc";
this.middleName = "middle1";

 var newToString = function(name){ //overwriting toString method
  console.log("The name is: "+name+"Middle Name is "+middleName);
 }
}

2: Classical way using 'new' keyword

    var newPerson = new familyTree();
    newPerson.firstName = "abc";
    newPerson.middleName = "middle1";
    newperson.newToString = function (name){
     console.log("The name is: "+name+"Middle Name is "+middleName);
    }

Let's say if I want to create 100 different middle names.

What makes more sense? Using Classical Inheritance or Prototypical? Because using Classical can copy over all the objects but using prototypical can get everything messy.

Please illustrate, when one should be using classical vs prototypical.

TechnoCorner
  • 4,879
  • 10
  • 43
  • 81
  • Neither of these are examples of inheritance, they are two different ways of adding properties to a specific instance. And, your first example has a syntax error on the first line. JavaScript only has prototypical inheritance. – Scott Marcus Feb 06 '17 at 04:14
  • And, your second example sets the 'firstName' property twice. – Scott Marcus Feb 06 '17 at 04:23
  • Properties should be defined in the constructor so that each new instance can store values that are independent of any other instance ("instance-specific"). Methods should be added to the constructor's prototype so that the function doesn't have to be stored as part of each instance, but all instances will still inherit the behavior. Behavior doesn't change from instance to instance, but data does. – Scott Marcus Feb 06 '17 at 04:27
  • @ScottMarcus thank you fixed. My bad that was a typo. – TechnoCorner Feb 06 '17 at 22:20

1 Answers1

2

There is only one kind of inheritance in JavaScript and that is prototypical inheritance. "Classical" inheritance doesn't exist in JavaScript.

Despite the "syntactic sugar" that the JavaScript language has to make OOP developers who are very comfortable with class-based programming feel at home (including the class keyword), JavaScript doesn't actually have or use classes. That language vocabulary is just meant to make you feel all warm and fuzzy.

Your question is not actually asking about inheritance, it's asking about whether properties should be attached to the constructor function or the prototype.

See the code comments for explanations:

// When you create a function that you will use to create object instances,
// you have a "constructor function". By convention, these functions should
// be named in PascalCase as a way to let others know that they are to be
// used in conjunction with the "new" keyword as a constructor.
function FamilyTree(first, middle, last){
  
  // Because this function will be used to create instances of a
  // FamilyTree object, each instance created will need to store
  // data that is different from another. This is done with "instance
  // properties" and they are created by prepending the property name
  // with "this.". The "this" object will be referenced by the object
  // instance variable that is used when the instance is created:
  this.firstName = first;
  this.middleName = middle;
  this.lastName = last;
  
}

// JavaScript objects don't technically have "methods" - - they
// have properties that store functions and functions are how
// to add behavior to an object. Since the behaviors of an object
// don't typically change from instance to instance, you should not
// add them to the constructor function. If you did, the code would
// work, but each instance would need to store a copy of the exact 
// same behavior, making the objects unnecessarialy large in memory.
// Instead, we attach behaviors that all instances of an object will
// need to the prototype of the constructor and that way all instances
// created from the constructor will inherit the behaviors, but the 
// acutal behavior will only be stored once, thus saving on memory space
// and eliminating the possibility of one instance behaving differently 
// than others, unintentionally.

// Implementing "methods" that all FamilyTree instances will inherit:
FamilyTree.prototype.newToString = function(name){ 
  return "First name: " + this.firstName + ", Last Name: " + this.lastName;
}

// The constructor function's prototype (as with all objects) derives from "Object"
// which defines a "toString" property, by re-defining that property on the constructor's
// prorotype, we will be able to override the inherited one
FamilyTree.prototype.toString = function(name){ 
  return this.lastName + ", " + this.firstName;
}
  
// To use this object, we have a few choices, but the simplest one is to just instantiate it:
var myFamilyTree = new FamilyTree("John","Fitzgerald","Kennedy");

// Now, we just work with the instance:
console.log(myFamilyTree.firstName);
console.log(myFamilyTree.middleName);
console.log(myFamilyTree.lastName);
console.log(myFamilyTree.newToString());
console.log(myFamilyTree.toString());

Now, the above code works, but is technically not organized well since the object is a "Family Tree" and all it really stores is a single person's name and some ways to output that name. Not much of a family tree. In reality, this "Family Tree" object should be made up from other objects (i.e. many individual people should be able to be included along with other pertinent family tree data). If we apply the OOP "Single Responsibility Principle" ("A class/module should have only one reason to change"), we would need to make the Family Tree object have smaller object parts. All this would involve is making the original object have a property that stores an array of people objects:

// First, make objects that represent the parts of the whole
function Person(first, middle, last, dob, maiden){
  // Instance properties are added to the constructor, which makes individual instances:
  this.firstName = first;
  this.middleName = middle;
  this.lastName = last;
  this.dob = dob;
  this.maidenName = maiden;
}

// Behavior properties are added to the constructor's prototype to avoid duplication
// of code across instances:
Person.prototype.newToString = function(name){ 
  return "First name: " + this.firstName + ", Last Name: " + this.lastName;
}

Person.prototype.toString = function(name){ 
  return this.lastName + ", " + this.firstName;
}

// Then create an object that becomes the sum of the parts:
function FamilyTree(){
  // We just need a way to store family members.
  // Each FamilyTree instance can have different members, so an instance property
  // is needed:
  this.people = [];
}

// And, again, behaviors are added to the prototype:
FamilyTree.prototype.getMemberCount = function(){
  return this.people.length;
}

FamilyTree.prototype.addMember = function(personObject){
  this.people.push(personObject);
}

FamilyTree.prototype.removeMember = function(personObject){
  var index = this.people.findIndex(function(element){
    return personObject === element;
  });
  this.people.splice(index, 1);
}

// And, because the tree stores an array, we can looop through it:
FamilyTree.prototype.enumerate = function(){
  var result = "";
  this.people.forEach(function(person){
    result += person.firstName + " " + person.middleName + " " + person.lastName + 
           " (" + person.newToString() + " [" + person.toString() + "])";
  });
  return result;
};

  
// Now, to use the Family Tree, we first need some people
var jack = new Person("John","Fitzgerald","Kennedy", new Date(1917, 4, 29));
var bobby = new Person("Robert", "Francis", "Kennedy", new Date(1925, 11, 20));
var teddy = new Person("Edward","Moore","Kennedy", new Date(1932, 1, 22));

// Now, we add those objects to a new Family Tree instance:
var kennedyTree = new FamilyTree();
kennedyTree.addMember(jack);
kennedyTree.addMember(bobby);
kennedyTree.addMember(teddy);
console.log("The tree contains: " + kennedyTree.getMemberCount() + " members.");
console.log(kennedyTree.enumerate());

// Let's remove a member:
kennedyTree.removeMember(bobby);
console.log("The tree contains: " + kennedyTree.getMemberCount() + " members.");
console.log(kennedyTree.enumerate());
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • So are you telling me that what I read in : http://stackoverflow.com/questions/19633762/classical-inheritance-vs-protoypal-inheritance-in-javascript is just a syntactic sugar (/gimmic) over prototypical inheritance? and the other article is incorrect? Because, in the solution, the author says that inheritance is divided into Prototypical and classical (Hence I'm confused) – TechnoCorner Feb 06 '17 at 22:22
  • @TechnoCorner Yes. In fact, if you read the answer on the post you reference, it says: *"Both the code samples you demonstrated in your question make use of prototypal inheritance. In fact any object-oriented code you write in JavaScript is a paradigm of prototypal inheritance. JavaScript simply doesn't have classical inheritance."* – Scott Marcus Feb 06 '17 at 22:29
  • @TechnoCorner What you are reading is about types of inheritance in general. But, from what I saw in that post and in those articles, they correctly indicate that JavaScript does not have classical inheritance. Understand that just because a language is Object-Oriented does not mean it must implement a particular type of inheritance - only that it must support some kind of inheritance. – Scott Marcus Feb 06 '17 at 22:36
  • @TechnoCorner I just read through that post you linked to, and I have to say, it's quite clear. I'm not sure what you are seeing that is leading you to believe the both prototypical and classical inheritance exist in JavaScript. – Scott Marcus Feb 06 '17 at 22:41
  • Thank you so much for enlightening me. Today I learned something new. You are awesome! – TechnoCorner Feb 06 '17 at 23:17
  • reading more and more raises more questions (Even though I'm understanding JS as more "prototypical pattern" vs constructor pattern).. When would be the scenario where I'd use constructor pattern over prototypical pattern? (or can we completely get rid of constructor pattern?) Kinda confused here. The reason why i'm asking is that, I'm in a debate as in why prototypical pattern is better than constructor pattern but it seems constructor pattern solves the use case when we need to extend a function's properties. Can you enlighten me in this scenario? PS: it's folks like you who make SO delight – TechnoCorner Feb 07 '17 at 02:27
  • @TechnoCorner Everything you need is in the article referenced in the link you shared with me (http://aaditmshah.github.io/why-prototypal-inheritance-matters/). It's important to understand that both approaches are "prototypical inheritance", it's just that using a constructor (`new`) was meant to make class-based developers feel more at home. `Object.create()` is a way around this, but they both do the same thing. This is about "patterns" - - one size doesn't fit all and you'll need to familiarize yourself with the pro's and con's of each to decide when either is appropriate. – Scott Marcus Feb 07 '17 at 15:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/135109/discussion-between-technocorner-and-scott-marcus). – TechnoCorner Feb 07 '17 at 19:33