What is polymorphism in JavaScript?
Asked Answered
W

7

112

I have read some articles on polymorphism. But I think I could not quite grasp the meaning of its importance. Most of the articles don't say why it is important and how I can achieve polymorphic behavior in OOP (of course in JavaScript).

I can not provide any code example because I haven't got the idea how to implement it, so my questions are below:

  1. What is it?
  2. Why we need it?
  3. How it works?
  4. How can I achieve this polymorphic behavior in JavaScript?

I have got this example. But it is easily understandable what will be outcome of this code. It doesn't give any clear idea about polymorphism itself.

function Person(age, weight) {
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo.";
    }
}
function Employee(age, weight, salary) {
    this.salary = salary;
    this.age = age;
    this.weight = weight;
    this.getInfo = function() {
        return "I am " + this.age + " years old " +
        "and weighs " + this.weight +" kilo " +
        "and earns " + this.salary + " dollar.";
    }
}

Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
  // The argument, 'obj', can be of any kind
  // which method, getInfo(), to be executed depend on the object
  // that 'obj' refer to.

function showInfo(obj) {
    document.write(obj.getInfo() + "<br>");
}

var person = new Person(50,90);
var employee = new Employee(43,80,50000);
showInfo(person);
showInfo(employee);
Wilke answered 24/12, 2014 at 21:16 Comment(4)
This question is probably too broad to work well with StackOverflow. The best we could do would be to link you to some other polymorphism explanation. StackOverflow is best at answering specific questions or clarifications about a specific problem, such as "Source said polymorphism was XYZ, but what does Y mean?"Memphis
you don't need it. at all. you don't even need classes in JS, and in fact, there are many other, arguably better, paradigms for app construction. apply/call/bind eliminates the need for homogeneity, and with soft-object, you can modify anything to suit your needs without pre-decorating it or inheriting special cases.Bouton
Polymorphism is not just related to OO, and it has many meanings. You may want to read this other answer under the questions Is Polymorphism Possible without Inheritance.Percutaneous
To inherit is usually done incorrectly in JavaScript. To create an instance of Parent to be used as the prototype of Child shows a lack of understanding of the role the constructor function and prototype play in defining and creatng an object. More information is available in this answer: https://mcmap.net/q/24597/-prototypical-inheritance-writing-up-duplicateColous
L
117

Polymorphism is one of the tenets of Object Oriented Programming (OOP). It is the practice of designing objects to share behaviors and to be able to override shared behaviors with specific ones. Polymorphism takes advantage of inheritance in order to make this happen.

In OOP everything is considered to be modeled as an object. This abstraction can be taken all the way down to nuts and bolts for a car, or as broad as simply a car type with a year, make, and model.

To have a polymorphic car scenario there would be the base car type, and then there would subclasses which would inherit from car and provide their own behaviors on top of the basic behaviors a car would have. For example, a subclass could be TowTruck which would still have a year make and model, but might also have some extra behaviors and properties which could be as basic as a flag for IsTowing to as complicated as the specifics of the lift.

Getting back to the example of people and employees, all employees are people, but all people are not employees. Which is to say that people will be the super class, and employee the sub class. People may have ages and weights, but they do not have salaries. Employees are people so they will inherently have an age and weight, but also because they are employees they will have a salary.

So in order to facilitate this, we will first write out the super class (Person)

function Person(age,weight){
 this.age = age;
 this.weight = weight;
}

And we will give Person the ability to share their information

Person.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo.";
};

Next we wish to have a subclass of Person, Employee

function Employee(age,weight,salary){
 this.age = age;
 this.weight = weight;
 this.salary = salary;
}
Employee.prototype = new Person();

And we will override the behavior of getInfo by defining one which is more fitting to an Employee

Employee.prototype.getInfo = function(){
 return "I am " + this.age + " years old " +
    "and weighs " + this.weight +" kilo " +
    "and earns " + this.salary + " dollar.";  
};

These can be used similar to your original code use

var person = new Person(50,90);
var employee = new Employee(43,80,50000);

console.log(person.getInfo());
console.log(employee.getInfo());

However, there isn't much gained using inheritance here as Employee's constructor is so similar to person's, and the only function in the prototype is being overridden. The power in polymorphic design is to share behaviors.

Limeade answered 24/12, 2014 at 21:48 Comment(18)
is getInfo method is overridden or employ's getinfo is accessed first because it is comes ahead of person's getinfo in employ's prototype chain?Wilke
@user3138436 - That is correct. The prototypal chain will be inspected for the first occurrence of getInfo which will be Employee's as it is higher in the chain than Person's. That was what I meant when I said "overridden".Limeade
so can i say polymorphism is a way to push children object's methods having similar name to its parent object's method forward in prototype chain in order to show different behavior for child objects(sub classes) ??Wilke
You're not re using the constructor (Person.call(this,arg)) and setting Employee prototype to an instance of Person. Prototype is where shared members go and constructor function is where the instance specific members are created. Your samples use copy paste code re use of constructor function and inherit the prototype part wrong (Person has instance specific members that have no business being on Employee.prototype especially if you'd have mutable members). More info about inheritance using constructor functions and prototype here: https://mcmap.net/q/24597/-prototypical-inheritance-writing-up-duplicateColous
For Employee to re use and extend getinfo of person it could simply do return Person.prototype.getInfo.call(this) + + "and earns " + this.salary + " dollar."; Instead of copy paste code re use.Colous
here where polymorphism applied?Krieg
It sounds like polymorphism is just the use of inheritance and overriding. If so, I have to admit that I'm surprised we have a completely separate term just describe those two things.Wring
@Wring the point of polymorphism can be seen better in the OPs example. the function showInfo(); accepts a general object. polymorphism now is the ability to react differently depending on the object type. i think this answer doesn't make this clear enough, since it calls getInfo() on every specific object.Kicker
What does line Employee.prototype = new Person(); do? Can I get some keywords to look online. Is it like calling super when an object in constructed?Plethora
> Polymorphism takes advantage of inheritance. OR implementing a common interface using composition is the other way to implement polymorphismKrutz
I didn't actually see anything in this answer explaining what polymorphism was. It only explained inheritance, which is a related but different concept. You can have polymorphism without inheritance.Puss
@Scotty Polymorphism without inheritance in JavaScript is generally implemented using the module pattern or similar, which works out okayish since JavaScript is duck typed (looks like a duck, quacks like a duck, is a duck). However, the explanation of using polymorphic behavior through inheritance is the soul of polymorhpism, and the non inheritance versions are merely caveats. Perhaps if you read through or do more research you will see that using inheritance to provide many different behaviors to existing hooks is more than simply adding new hooks with concrete implementations of interfaces.Limeade
I like the go lang's approach to inheritance - they just ripped out polymorphism from inheritance and rebranded it as "embedding". The fact that you're using embedding is a private implementation detail instead of publicly exposed relationship information. If you want to achieve polymorphism in go, you have to use interfaces. Inheritance ≠ polymorphism. Inheritance is often overused because people keep trying to use it to achieve polymorphism, not because they actually need to inherit behaviors. People need to know that alternatives solutions exist, such as duck typing, protocols, etc.Puss
@ScottyJamison - I am afraid you are misunderstanding polymorphism as only inheritance, which is a common mistake. It isn't about inheriting behaviors so much as allowing behaviors to be altered by the defining class. This allows a super type to be expected with behavior X, and the sub type to be actually used whereby the sub type defines the behavior X. Any number of different sub types can take the place of the super expectation, thus allowing for example a routine to call honk on your car, and your car may define the style of honk it uses. It is a separation of concerns aspect of OOP.Limeade
Duck typing and protocols are not alternatives to polymorphishm, and what people really need is to have -- especially in today's environment -- is correct, accurate information. Your information is neither correct nor accurate. Merely using an interface does not mean that you are only using inheritance. Go may be an interesting language, but it has no bearing on the principle of polymorphism.Limeade
OK, I think I know where we're getting confused at. What you're calling "polymorphism" is really just a specific form of polymorphism - "subtype polymorphism". In OOP often when people speak of polymorphism they're just talking about the subtype variant, but that's not the only kind that exists - there's other ways to reap the benefits of polymorphism. You can read the other answers or peak at wikipedia for other varients of polymorphism. (other answers also indicate that duck typing is indeed a form of polymorphism).Puss
I would define polymorphism somewhat like "The ability for an operation/function to use different types of things/objects without singling out and handling each type in the operation's definition". Inheritance is one way to do this. So is duck typing, prototypes (like the iterable prototype), interfaces, well-known functions like .toString(), etc. To quote wikipedia: "polymorphism is the provision of a single interface to entities of different types or the use of a single symbol to represent multiple different types" - This definition puts emphasis on interfaces and types, not on inheritance.Puss
Yes, interfaces and types. That is the defined contract, and the concrete implementation is how shared behaviors are implemented. Primarily the implementation is through a virtual function, in JavaScript, that means defining the same function with the same signature but a more custom behavior. In this fashion, the function can be called without concern of the outcome, so long as it adheres to being the right type. As JavaScript itself is not strongly typed (there are transpiled versions which do) it just assumes that members are available through loosely ("duck") typed approaches.Limeade
P
31

As explained in this other answer, polymorphism has different interpretations.

The best explanation on the subject that I've ever read is an article by Luca Cardelli, a renowned type theorist. The article is named On Understanding Types, Data Abstraction, and Polymorphism.

What Is it?

Cardelli defines several types of polymorphism in this article:

  • Universal
  • parametric
  • inclusion
  • Ad-hoc
  • oveloading
  • coercion

Perhaps in JavaScript, it is a bit more difficult to see the effects of polymorphism because the more classical types of polymorphism are more evident in static type systems, whereas JavaScript has a dynamic type system.

So, for instance, there is no method or function overloading or automatic type coercions at compile time in JavaScript. In a dynamic language, we take most of these things for granted. Neither we need something like parametric polymorphism in JavaScript due to the dynamic nature of the language.

Still, JavaScript has a form of type inheritance that emulates the same ideas of subtype polymorphism (classified as inclusion polymorphism by Cardelli above) in a similar way to what we typically do in other object-oriented programing languages like Java or C# (as explained in another answer I shared above).

Another form of polymorphism very typical in dynamic languages is called duck typing.

It is a mistake to believe that polymorphism is only related to object-oriented programming. Other programming models (functional, procedural, logic, etc.) offer different forms of polymorphism in their type systems, probably in a way a bit unfamiliar to those only used to OOP.

Why We Need It?

Polymorphism foster many good attributes in software, among other things it fosters modularity and reusability and makes the type system more flexible and malleable. Without it, it would be really difficult to reason about types. Polymorphism makes sure that one type can be substituted by other compatible ones provided that they satisfy a public interface, so this also fosters information hiding and modularity.

How Does it Work?

This is not simple to answer, different languages have different ways to implement it. In the case of JavaScript, as mentioned above, you will see it materialize in the form of type hierarchies using prototypal inheritance and you can also exploit it using duck typing.

The subject is a bit broad and you opened too many questions in a single post. Perhaps it is best that you start by reading Cardelli's paper and then try to understand polymorphism irrespective of any language or programming paradigm, then you will start making associations between the theoretical concepts and what any particular language like JavaScript has to offer to implement those ideas.

Percutaneous answered 24/12, 2014 at 22:44 Comment(0)
P
19

What is the purpose of polymorphism?

Polymorphism makes a static type system more flexible without losing (significant) static type safety by loosening the conditions for type equivalence. The proof remains that a program will only run if it doesn't contain any type errors.

A polymorphic function or data type is more general than a monomorphic one, because it can be used in a wider range of scenarios. In this sense polymorphism represents the idea of generalization in strictly typed languages.

How does this apply to Javascript?

Javascript has a weak, dynamic type system. Such a type system is equivalent with a strict type system containing only one type. We can think of such a type as a huge union type (pseudo syntax):

type T =
 | Undefined
 | Null
 | Number
 | String
 | Boolean
 | Symbol
 | Object
 | Array
 | Map
 | ...

Every value will be associated to one of these type alternatives at run-time. And since Javascript is weakly typed, every value can change its type any number of times.

If we take a type theoretical perspective and consider that there is only one type, we can say with certainty that Javascript's type system doesn't have a notion of polymorphism. Instead we have duck typing and implicit type coercion.

But this shouldn't keep us from thinking about types in our programs. Due to the lack of types in Javascript we need to infer them during the coding process. Our mind have to stand in for the missing compiler, i.e. as soon as we look at a program we must recognize not only the algorithms, but also the underlying (maybe polymorphic) types. These types will help us to build more reliable and more robust programs.

In order to do this properly I am going to give you an overview of the most common manifestations of polymorphism.

Parametric polymorphism (aka generics)

Parametric polymorphism says that different types are interchangeable because types doesn't matter at all. A function that defines one or more parameters of parametric polymorphic type must not know anything about the corresponding arguments but treat them all the same, because they can adopt to any type. This is quite restricting, because such a function can only work with those properties of its arguments that are not part of their data:

// parametric polymorphic functions

const id = x => x;

id(1); // 1
id("foo"); // "foo"

const k = x => y => x;
const k_ = x => y => y;

k(1) ("foo"); // 1
k_(1) ("foo"); // "foo"

const append = x => xs => xs.concat([x]);

append(3) ([1, 2]); // [1, 2, 3]
append("c") (["a", "b"]); // ["a", "b", "c"]

Ad-hoc polymorphism (aka overloading)

Ad-hoc polymorphism says that different types are equivalent for a specific purpose only. To be equivalent in this sense a type must implement a set of functions specific to that purpose. A function that defines one or more parameters of ad-hoc polymorphic type then needs to know which sets of functions are associated to each of its arguments.

Ad-hoc polymorphism makes a function compatible to a larger domain of types. The following example illustrates the "map-over" purpose and how types can implement this constraint. Instead of a set of function the "mappable" constraint only includes a single map function:

// Option type
class Option {
  cata(pattern, option) {
    return pattern[option.constructor.name](option.x);
  }
  
  map(f, opt) {
    return this.cata({Some: x => new Some(f(x)), None: () => this}, opt);
  }
};

class Some extends Option {
  constructor(x) {
    super(x);
    this.x = x;
  }
};

class None extends Option {
  constructor() {
    super();
  }
};


// ad-hoc polymorphic function
const map = f => t => t.map(f, t);

// helper/data

const sqr = x => x * x;

const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();

// application

console.log(
  map(sqr) (xs) // [1, 4, 9]
);

console.log(
  map(sqr) (x) // Some {x: 25}
);

console.log(
  map(sqr) (y) // None {}
);

Subtype polymorphism

Since other answers already cover subtype polymorphism I skip it.

Structural polymorphism (aka strutrual subtyping)

Structural polymorphism says that different types are equivalent, if they contain the same structure in such a way, that one type has all the properties of the other one but may include additional properties. That being said, structural polymorphism is duck typing at compile time and certainly offers some additional type safety. But by claiming that two values are of the same type just because they share some properties, it completely ignores the semantic level of values:

const weight = {value: 90, foo: true};
const speed =  {value: 90, foo: false, bar: [1, 2, 3]};

Unfortunately, speed is considered a subtype of weight and as soon as we compare the value properties we are virtually comparing apples with oranges.

Peddling answered 26/11, 2016 at 9:43 Comment(3)
While this is in many respects more accurate (and certainly more thorough) than the accepted answer, it does not have the same accessibility: this answer presumes that the asker is already too smart to bother with the question :)Chancellorsville
@JaredSmith I tried to boil down the subject to some easy to grasp paragraphs. But the deeper I drill the more complex it gets. I've never found a good source for polymorphism in untyped languages, therefore I think this answer is nevertheless valuable.Peddling
the edit greatly improves the accessibility. As for the usefulness of polymorphism in dynamic languages, there are plenty but I'm struggling to think of a good example in JS. A better example would be Python's magic methods that allow user-defined types to work with polymorphic functions like len. Or perhaps conj from clojure.Chancellorsville
D
9

what is it?

Poly= many, morphism=form or behavior shifting.

why we need it ?

In programming, It is used when we want a function's (let say function X's) interface to be flexible enough to accept different types or number of parameters. Also, based on changing parameters types or numbers, we might want the function X to behave differently (morphism).

How it works?

We write multiple implementations of X function where each implementation accepts different parameters types or number of parameters. Based on the type or number of parameter, the compiler (at runtime) decides which implementation of X should be executed when X is called from some code.

how can I achieve this polymorphic behavior in javascript?

JS is not a typed language so it really not meant to use OOP concepts like polymorphism. However, the newer version of JS now include classes and there is possibility that polymosphism could start making sense in JS, too. Other answers provide some interesting workarounds.

Denby answered 16/12, 2016 at 8:12 Comment(0)
A
7

Polymorphism means Ability to call the same method on different objects and each object responds in different way is called POLYMORPHISM.

    function Animal(sound){
    this.sound=sound;
    this.speak=function(){
    			return this.sound;
    	}
    }
//one method 
    function showInfo(obj){
    		console.log(obj.speak());
    }
//different objects
    var dog = new Animal("woof");
    var cat = new Animal("meow");
    var cow = new Animal("humbow");
//responds different ways
    showInfo(dog);
    showInfo(cat);
    showInfo(cow);
Abm answered 28/8, 2018 at 11:19 Comment(0)
P
3

JavaScript is an interpreted language, not a compiled language.

Compile time Polymorhism( or Static polymorphism) Compile time polymorphism is nothing but the method overloading in java,c++

So method overloading is not possible in javascript.

But Dynamic (run time) polymorphism is the polymorphism existed at run-time so method overriding is possible in javascript

another example is PHP.

Pieria answered 4/5, 2017 at 7:44 Comment(0)
S
2

Polymorphism is the ability to define a generic type of behaviour that will behave differently when applied to different types.

Let's say we have an Animal class that implements the talk method. If class Dog and Cat inherit talk() from class Animal, object dog and object cat both will talk but in a different form.

When we iterate over a collection, that collection has to support the iterable protocol. It does not matter the form of the collection object whether it is an array or dictionary.

+,-,*,/ operators are polymorphic. Because they work with different types: complex numbers, decimal, integer.

The main benefit of polymorphism is resuing the code. If you have duplicate code, you need extra space in memory which decreases the performance and also you need someone or something to maintain that duplicate code.

Since you reusing the single code, it helps debug your code easily

Su answered 17/7, 2021 at 3:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.