1

I'm new to programming and am trying to understand inheritance in JS. I was reading JavaScript Objects in Detail and could not discern the significance of the empty constructor in this example. Consider this:

function Fruit () {

}

Fruit.prototype.color = "Yellow";
Fruit.prototype.sweetness = 7;
Fruit.prototype.fruitName = "Generic Fruit";
Fruit.prototype.nativeToLand = "USA";

Fruit.prototype.showName = function () {
    console.log("This is a " + this.fruitName);
}

Fruit.prototype.nativeTo = function () {
    console.log("Grown in:" + this.nativeToLand);
}

var mangoFruit = new Fruit ();

How is this any better than defining a constructor with the same properties as arguments?

Also, if browser support isn't a concern would using Object.create() be preferable to using either a constructor or using prototype for inheritance?

Bitter
  • 156
  • 1
  • 6
  • 1
    Properties on the prototype are shared with all instances. Properties declared in the constructor are unique to each instance. – elclanrs Mar 14 '14 at 00:20
  • I wrote another answer today about this... http://stackoverflow.com/a/22385426/3203588 – Oscar Paz Mar 14 '14 at 00:25
  • Thank you both, that makes sense. I guess my question then is when would one be preferable over the other? – Bitter Mar 14 '14 at 00:33

4 Answers4

3

Actually, your example (in this case) isn't better. You've defined properties and methods that are shared with all fruits (via the prototype), but not all fruits are yellow or have a sweetness of 7. In this case, these would make sense as passed arguments and defined in each instance (using this.color within your constructor).

So when would you choose one over the other? Let's go back to fruit - there are shared actions with fruits that we can do (for instance, eat and peel) - those could be methods of your prototype. These methods are defined once, and all instances refer to the same method.

Things that are unique (color, sweetness) make sense as instance properties (passed in via an argument).

As stated above, the other advantage of prototype methods is this: They're a single reference. Calling new Fruit() a thousand times will create a thousand instances of Fruit, but they all will reference that single prototype method (for example, eat).

Jack
  • 9,151
  • 2
  • 32
  • 44
1

You've got inheritance wrong with your example, as all the object will be sharing the same properties. You have to divide your prototype chain in order to organize the common properties at the bottom, while the more specific properties of that object end up at the top of the chain.

Consider this:

Imagine you have a box where you keep folders. Each folder has contain information about cars. Imagine you want to write information about a Mitsubishi Lancer Evolution VII. Inside your folder you write all the information about the brand, model, edition, etc. Now you add other folder for the Mitsubishi Lancer Evolution VI and write everything, and then for the Mitsubishi Eclipse, Toyota Supra, etc.

Soon you will be realizing that the box get full quickly, it is hard to get an specific information fast, and you are writing the same thing many times. Then you realizes that you can have a folder for the Mitsubishi brand information, and every Mitsubishi car folder has a reference that says "Brand: see Mitsubishi folder". Then you realize that you can do the same with the Lancer Evolution model. A lot of repeated information get removed, the box has more space, it is easier to add new files, it is faster to search for specific information...

Now think that the box is the computer memory, then brand, model, edition, etc. are objects, information in your file is object properties, brand is for model as a prototype for an object.

So, your car object will be as:

var Brand = function Brand(brand){
    this.brand = brand ;
    this.Model = function Model(model){
        this.model = model ;
        this.Edition = function Edition(edition){
            this.edition = edition ;
        } ;
        this.Edition.prototype = this ;
    } ;
    this.Model.prototype = this ;
} ;

var Mitsubishi = new Brand('Mitsubishi') ;
var LancerEvolution = new Mitsubishi.Model('Lancer Evolution') ;
var LancerEvolutionVII = new LancerEvolution.Edition('VII') ;
var LancerEvolutionVI = new LancerEvolution.Edition('VI') ;

So:

LancerEvolutionVII.brand == 'Mitsubishi' // true
LancerEvolutionVII.model == 'LancerEvolution' // true
LancerEvolutionVII.edition == 'VII' // true

The cool thing is that for every Mitsubishi car there is only one object Brand, and all share it. So if Mitsubishi company changes name tomorrow you only need to do:

Mitsubishi.brand = 'NewCompanyName' ;

and all your Mitsubishi cars will have the brand updated.

I hope this helped you, ask whatever doubt you are still having.

Juan Garcia
  • 714
  • 6
  • 23
  • Why do Model and Edition need to be re defined on every Brand creation? Can't Edition inherit from Model and Model from Brand? – HMR Mar 14 '14 at 01:36
  • @HMR To bind it's on Brand prototype. That way all Mitsubishi cars share the same brand and all the Toyota shares the same brand, but Toyota brand is not the same as Mitsubishi brand. This is my personal way of doing it, but IMHO I think it is the most elegant. All it is self contained and prototypes are specific for the brand. It's a way to extend without contaminating the global scope with lot of constructors or declaring more variables in the outer scope – Juan Garcia Mar 14 '14 at 01:52
  • Then Edition can have an instance of Brand and Model can have an instance of Edition. No need to re define Edition and Model when creating a Brand. Or when you inherit you can pass a Model to Edition and a Brand to Model either use that in your constructor or other passed values. Can I edit your post to show you what I mean? – HMR Mar 14 '14 at 01:59
  • Edited: Consider this function in a Brand wrapping scope: `var newVersion(version){ return new (new this.Model(this.model)).Edition(version) ; }` and in Model scope `this.Edition.prototype.newVersion = newVersion ;` it will let you construct a new version like this: `LancerEvolutionVIII = LancerEvolutionVII.newVersion('VIII') ;` and will be still using that specific prototype chain. – Juan Garcia Mar 14 '14 at 02:12
1

would using Object.create() be preferable to using either a constructor or using prototype for inheritance?

That doesn't make much sense, Object.create returns the object in the second argument (or empty object) with the first argument as it's prototype. You can polyfil it for older browsers but can't use the second argument. So you're not using Object.create instead of prototype, you're still using prototype.

To define an object you need to define a function that will initialize instance specific members (this.name, this.age) and define shared members (prototype.getName, prototype.getAge). When creating an object you need to run the initializer to initialize the instance members. This could be a constructor function but there are other patterns.

The code you show is a one way to set default values (works only on primitive types), I prefer to pass one object to a constructor function and have the constructor function code figure out how to set defaults or throw on missing or invalid arguments (see link below under "Passing (constructor) arguments").

For a detailed explanation of prototype and constructor functions see this answer.

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160
0

I think it's the difference between prototype inheritance vs class inheritance, so it is confusing when coming from a programming language that has special syntax for creating classes. Also you can access the constructor in javascript and modify constructor. The constructor property of an object can be changed. If the constructor property is overwritten, the original value will simply be lost.

I highly recommend Chapter 6 from the book Secrets of a Javascript Ninja by John Resig. I have read it a couple times, but still something new.

Prototype languages are generally quite malleable. You can change any slot on any object. - From Seven languages in Seven Weeks Chapter 3, IO language, which is also a prototype language

function Ninja() {

}

it("The ninja object was created by the Ninja function", function () {
    var ninja = new Ninja();
    expect(ninja.constructor == Ninja).toEqual(true);
});
aarti
  • 2,815
  • 1
  • 23
  • 31
  • Thank you. I'm still unclear as to why would one use classical inheritance over using prototype? – Bitter Mar 14 '14 at 00:37
  • Flexibility is one reason. – aarti Mar 14 '14 at 00:43
  • Actually (if I understand you correctly) you can modify prototype functions. Here's a fiddle demonstrating: http://jsfiddle.net/fVjPT/ – Jack Mar 14 '14 at 00:48
  • 1
    @Bitter—it depends on the use case. Each has features and depending on the circumstance, one set of features may fit better than the other. Or not. – RobG Mar 14 '14 at 00:50
  • @JackPattishallJr. you are right, I updated my answer. – aarti Mar 14 '14 at 01:20