JavaScript does not provide class inheritance in traditional object-oriented languages, but implements object to object inheritance in the form of prototype delegation. There is also no support for abstract classes and interfaces in JavaScript. Because JavaScript itself is a type-fuzzy language. This may be a shade, but can also be said to be a free and easy.

Before we dive into design patterns, it’s important to understand some of the object-oriented aspects of JavaScript.

1. Dynamically typed languages and duck types

Programming languages fall into two categories by data type:

  • Static language types:Statically typed languages determine the type of a variable at compile time
    • Advantages: Type mismatch errors can be found at compile time, which can avoid some errors that may occur when the program is running, and improve the execution speed of the program to a certain extent.
    • Cons: Type declarations increase the amount of code you write, distracting you from the business logic in the process. After all, most of us write programs to deliver.
  • Dynamically typed languages:The type of a variable is determined at run time and does not have a type until the variable is assigned a value. (JavaScript is, of course, a dynamic language type)
    • Pros: Less code and a cleaner look. We can put more experience into business logic.
    • Disadvantages: Variable types cannot be guaranteed.

The tolerance of dynamically typed languages for variables actually gives coding a lot of flexibility. It all builds on the concept of duck typing.

Duck type: If it walks like a duck and quacks like a duck, it’s a duck.

We can learn about duck types through a story:

The king thought the sound of ducks was so wonderful that he decided to form a choir of 1,000 ducks. But there are only 999 ducks in the world, and there is one very special chicken. The chicken sounds like a duck, so the chicken becomes a member of the choir.

The lesson of this story is that duck types focus only on the behavior of the object, not on the object itself.

let duck = {
  duckSinging: () = > {
    console.log("Quack quack."); }};let chicken = {
  duckSinging: () = > {
    console.log("Quack quack."); }};let choir = [];

let joinChoir = (animal) = > {
  if (animal && typeof animal.duckSinging === "function") {
    choir.push(animal);
    animal.duckSinging();
    console.log("Congratulations on joining the glee club.");
    console.log(Current members of the Choir:${choir.length}`); }}; joinChoir(duck); joinChoir(chicken);/ / ga ga ga
// Congratulations on joining the choir
// Current members of choir: 1
/ / ga ga ga
// Congratulations on joining the choir
// Current members of choir: 2
Copy the code

Summary: In the object-oriented design of dynamically typed languages, the concept of duck type is so important that we are equivalent to “interface programming.” For example, an object with push and pop methods can be used as a stack if these methods provide the correct implementation. If an array has a length attribute and can be accessed by subscript (preferably with methods such as slice and splice), the object can be used as an array.

2. Polymorphism

The actual meaning of polymorphism is that the same operation on different objects can produce different interpretations and different execution results. In other words, when you send the same message to different objects, they give different responses based on the message.

Let’s take a quick story to understand:

The host has a duck and a chicken. When the host commands them to “crow”, the duck will “quack quack” and the chicken will “cluck”. “They’re both animals and they both make calls,” but they each make different calls when instructed by their owners

And therein lies the idea of polymorphism.

Let’s look at a piece of “polymorphic” code.

let makeSound = (animal) = > {
  if (animal instanceof Duck) {
    console.log("Quack quack.");
  } else if (animal instanceof Chicken) {
    console.log("Cluck cluck."); }};let Duck = function () {};
let Chicken = function () {};

makeSound(new Duck());
makeSound(new Chicken());

/ / ga ga ga
/ / luo luo luo
Copy the code

This code does represent “polymorphism,” but it is clearly not satisfactory. Why is that? Imagine adding another animal, like a dog or a cat. It’s obviously not a cluck or a quack quack. In this case we need to change the makeSound function and continue to stack it with an if else statement. Changing code is always dangerous; the more you change it, the more likely it is that something will go wrong. With more animals, the makeSound function has the potential to become huge.

A good code would look something like this.

let makeSound = (animal) = > {
  if (animal.sound && typeof animal.sound === "function") { animal.sound(); }};let Duck = function () {};
Duck.prototype.sound = () = > {
  console.log("Quack quack.");
}

let Chicken = function () {};
Chicken.prototype.sound = () = > {
  console.log("Cluck cluck.");
}

let Dog = function () {};
Dog.prototype.sound = () = > {
  console.log(Woof woof woof);
}

makeSound(new Duck());
makeSound(new Chicken());
makeSound(new Dog());

/ / ga ga ga
/ / luo luo luo
/ / auf
Copy the code

This makes it intuitive to see that when the animals are added, we don’t need to touch the old makeSound function, just add some code.

The central idea of polymorphism is to separate the “what” from the “who” and “how”, the “immutable” from the “mutable”. This gives us the ability to scale applications that appear to be growable and follow the open-closed principle. It’s much more elegant and secure to append new code to do the same thing than to modify previous code.

2.1 The role of polymorphism in object-oriented programming

The fundamental function of polymorphism is to eliminate procedural conditional branching statements by converting them into object polymorphism.

Let’s use a short story to understand polymorphism better.

When a crew is shooting, lighting, actors and cameramen all have different responsibilities. When the director calls out “Action”, everyone has to do their own thing. Without polymorphic thinking, everyone would have to come to the director and “take action” when the director calls out “action”. With polymorphic thinking, what these people need to do has been assigned to each of their objects. Just wait for the director’s “action” and do your own thing right away.

See the code above for eliminating if else.