2

Most languages use single inheritance for classes. And it's fairly obvious the pattern to do this (for example in Swift code below). I am still trying to wrap my head around the pattern in JavaScript to create a object hierarchy and re-use class functions and override class functions

class animal {
    func talk() {
        print ("?")
    }
}

class bird : animal {
    override func talk() {
        print("tweet tweet")
    }
    func fly() {
        print("flap flap")
    }
}

class parrot : bird {
    override func talk() {
        print("polly want a cracker")
    }
}

var a = animal()
var b = bird()
var p = parrot()

a.talk()  /// ?
b.talk()  /// tweet tweet
b.fly()   /// flap flap
p.talk()  /// polly want a cracker
p.fly()   /// flap flap

I think my problem is the Javascript code looks nothing like this. What is the equivalent Javascript code so I can figure out the pattern?

swdev
  • 2,941
  • 2
  • 25
  • 37
  • Possible duplicate of [what is polymorphism in Javascript](http://stackoverflow.com/questions/27642239/what-is-polymorphism-in-javascript) – Heretic Monkey Jun 28 '16 at 21:59
  • Well, not to nitpik but that question was sort of cluttered with the "what is" part of the question. I have no problem with that just need a clean one-to-one comparison of "how" to convert it. – swdev Jun 28 '16 at 22:05

2 Answers2

8

You pretty much answered your own question. You just have to learn JavaScript's syntax for it.

I think my problem is the Javascript code looks nothing like this.

  1. It's not a "problem" for you if a language looks different from another one

  2. The Swift code you provided is syntactically very close to the JavaScript (ES6) you'd need to write to express the same hierarchy of classes

class Animal {
  talk() {
    console.log('?')
  }
}

class Bird extends Animal {
  talk() {
    console.log('tweet tweet')
  }
  fly() {
    console.log('flap flap')
  }
}

class Parrot extends Bird {
  talk() {
    console.log('polly want a cracker')
  }
}

var a = new Animal()
var b = new Bird()
var p = new Parrot()

a.talk()
b.talk()
b.fly()
p.talk()
p.fly()

If you want to setup a "class" inheritance in ES5, you can do this

// Animal "class"
function Animal() {}

// Animal methods
Animal.prototype.talk = function talk() {
  console.log('?')
}

// ------------------------------
// Bird "class"
function Bird() {
  // if you want to call the parent constructor, you can do that here
  // Animal.call(this, arg1, arg2, ... argN)
}

// Bird inherits from Animal
Bird.prototype = Object.create(Animal.prototype)
Bird.prototype.constructor = Bird

// Bird methods
Bird.prototype.talk = function() {
  console.log('tweet tweet')
}
Bird.prototype.fly = function() {
  console.log('flap flap')
}

// ------------------------------
// Parrot "class"
function Parrot() {
  // if you want to call the parent constructor, you can do that here
  // Bird.call(this, arg1, arg2, ... argN)
}

// Parrot inherits from Bird
Parrot.prototype = Object.create(Bird.prototype)
Parrot.prototype.constructor = Parrot

// Parrot methods
Parrot.prototype.talk = function() {
  console.log('polly want a cracker')
}

var a = new Animal()
var b = new Bird()
var p = new Parrot()

a.talk()
b.talk()
b.fly()
p.talk()
p.fly()
Mulan
  • 129,518
  • 31
  • 228
  • 259
  • I thought the "class" keyword was not supported in Javascript? – swdev Jun 28 '16 at 21:59
  • ES6 supports the `class` keyword. It is a syntactic sugar and the exact same code can be represented in ES5 or lower. – Mulan Jun 28 '16 at 22:00
  • 1
    Thanks. Exactly what I needed. Btw, the answers to the so called duplicate question didn't even mention the ES6 way and that is what I was after. – swdev Jun 29 '16 at 05:47
  • @naomik So basically `talk()` method of animal is overridden in bird and parrot? – kittu Jul 01 '17 at 12:50
  • @naomik Also can we do overloading ? – kittu Jul 01 '17 at 12:51
  • Only a few de facto operator overloads are supported, by implementing toString() and toPrimitive(). You can also read up on what's called "well-defined Symbols" to overload more operators in ES6, but method overloading is not supported in JavaScript, at least not the way C(++) and Java can do it. You'd need to use some sort of utility that can multiplex a function into multiple functions based on the length and/or type of arguments passed – Patrick Roberts Jul 01 '17 at 14:09
  • @swdev if you see code that looks like this: var somecls = function(args){ this.name = args.name; this.returnname = function(){ return this.name; } }; this is the most common way you'll probably see it done with ecma5 or less. the class keyword is really not required at all for the language to simulate a class. to use the class above and instantiate an object of it: var someobj = new somecls({name: 'Joe'}) In the above example, args are required for the constructor to set the property of name upon instantiation. – simon Sep 08 '17 at 02:47
  • @Satyadev there is no overloading mechanism in JavaScript due to it's extremely weak type system – Mulan Sep 08 '17 at 02:56
  • @Satyadev the `talk` function is "overridden" but ability to utilize the parent function remains via application of `Function.prototype.call` or `Function.prototype.apply` – Mulan Sep 08 '17 at 02:59
2

There are two answers, ES6:

class animal {
    talk() {
        console.log("?")
    }
}

class bird extends animal {
    talk() {
        console.log("tweet tweet")
    }
    fly() {
        console.log("flap flap")
    }
}

class parrot extends bird {
    talk() {
        console.log("polly want a cracker")
    }
}

var a = new animal()
var b = new bird()
var p = new parrot()

a.talk()  /// ?
b.talk()  /// tweet tweet
b.fly()   /// flap flap
p.talk()  /// polly want a cracker
p.fly()   /// flap flap

and ES5:

function animal() {

}

animal.prototype.talk = function () {
    console.log("?")
};

function bird() {
    animal.call(this)
}

bird.prototype = Object.create(
    animal.prototype,
    {constructor: {value: bird}}
);

bird.prototype.talk = function () {
    console.log("tweet tweet")
};

bird.prototype.fly = function () {
    console.log("flap flap")
};

function parrot() {
    bird.call(this);
}

parrot.prototype = Object.create(
    bird.prototype,
    {constructor: {value: parrot}}
);

parrot.prototype.talk = function () {
    console.log("polly want a cracker")
};


var a = new animal()
var b = new bird()
var p = new parrot()

a.talk()  /// ?
b.talk()  /// tweet tweet
b.fly()   /// flap flap
p.talk()  /// polly want a cracker
p.fly()   /// flap flap
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • What is `bird.call(this)` doing ? – kittu Jul 01 '17 at 12:52
  • It's invoking the bird constructor to make the instance of parrot initialize itself as a bird. If there was anything in the bird constructor or animal constructor, that would be executed. – Patrick Roberts Jul 01 '17 at 14:04
  • Thanks for your reply. One more quick question. Why do we have to point the constructor back to parrot as in `{constructor: {value: parrot}` ?? What happens if we don't? – kittu Jul 01 '17 at 14:11
  • If you don't, it's not usually important, but it would cause parrot.prototype.constructor === bird. This wouldn't cause new parrot() to create just a bird, so it's not a big deal, but the point of the ES5 syntax is to show almost exactly what ES6 syntax is doing, except for a couple techniques that would otherwise make the code completely unreadable (like making each of the prototype methods non-enumerable like it does with ES6 class for example) – Patrick Roberts Jul 01 '17 at 14:18