Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Полиморфизм JS: Программирование, управляемое данными

Корректировка к слайду «Параметрический полиморфизм»:

append(numbers1, numbers2);
append(strings1, strings2);

--

В этом уроке мы поговорим немножко о терминах и о такой вещи, как полиморфизм.

Что такое полиморфизм?

В языках программирования и теории типов полиморфизмом 
называется способность функции обрабатывать данные разных типов.

На практике

Полиморфизм повышает коэффициент повторного использования кода,
то есть уменьшает дублирование.

Виды полиморфизма

  • Ad-hoc (Специальный)
  • Параметрический
  • Подтипов (включения)

Со всеми примерами этих полиморфизмов мы уже встречались, но просто никогда не использовали эти термины.

Параметрический полиморфизм

Вызов ОДНОГО и того же кода для ВСЕХ
допустимых типов (полиморфных) аргументов.

Параметрический полиморфизм в теории типов и у людей, которые часто используют функциональные языки, обычно принято называть словом полиморфизм, что кстати говоря идёт в разрез с тем, что принято у программистов, которые пишут исключительно на объектно-ориентированных языках. Они под словом полиморфизм понимают полиморфизм подтипов.

Давайте представим ситуацию, с которой мы уже сталкивались. У нас есть список и мы вызываем операцию «собрать два списка в один»:

const numbers1 = l(3, 4, 5, 8);
const numbers2 = l(3, 2, 9);
append(numbers1, numbers2); // (3, 4, 5, 8, 2, 9)

append берет два списка и делает из них один.

Ещё один пример той же самой операции, но разница в том, что теперь здесь список строк:

const strings1 = l('cat', 'dog');
const strings2 = l('table', 'milk', 'phone'); 
append(strings1, strings2); // (cat, dog, table, milk, phone)

https://repl.it/@hexlet/js-ddp-polymorphism-parametric-polymorphism

Поскольку мы работаем в динамическом языке нам без разницы с какими типами работать. Какой бы список у нас не был и какой бы тип не содержался внутри какого-то основного типа – всё будет работать.

В статических языках это совершенно не так и вы не можете просто так определить список чего угодно. У вас будет список конкретных структур, поэтому в таких языках нужны специальные механизмы, которые позволяют определять обобщённые списки.

Это важно по той простой причине, что применяя функцию append (операция объединения списков) можно увидеть, что над элементами, которые лежат в списке, никаких действий не производится вообще. Они не участвуют в этой операции и им не нужно это. То есть объединяя два списка мы не делаем никаких преобразований внутри. Соответственно, эта операция в общем случае не зависит от того, что хранится внутри.

Идеально – язык программирования должен позволять нам работать с этим именно так.

Как я уже говорил, в динамических языках мы получаем параметрический полиморфизм из коробки и действительно – функция append одна для любых списков, потому что мы не делаем здесь никаких различий, код будет один и его будет довольно мало.

В статических языках нет механизма для поддержки параметрического полиморфизма, им придётся писать функцию append для каждого типа. Представьте себе сколько может быть списков и сколько вообще может быть таких структур, для которых придётся так делать. По этой причине там существуют специальные механизмы. Особенно эти проблемы существуют в объектно-ориентированных языках, потому что в функциональных языках параметрический полиморфизм есть всегда и из коробки – это основа, а вот например, в таких языках как Java, существует специальный механизм, который называется дженерики. В C++ существует механизм, который называется темплейты.

В каких-то других языках это может называться по другому, но всё это сводится к тому, чтобы иметь возможность пользоваться параметрическим полиморфизмом у себя в языке.

Ad-hoc полиморфизм

Это самый простой тип полиморфизма. Он связан с тем, что в зависимости от типов аргументов применяется разная реализация какой-то операции.

Например, в данном случае сложения:

1 + 1; // 2
'cat' + 'dog'; // catdog

console.log(1034.98); // => 1034.98
console.log('hello'); // => hello

https://repl.it/@hexlet/js-ddp-polymorphism-ad-hoc-polymorphism

Если у нас типы число и число, то у нас будет арифметическая операция. Если у нас две строчки, то это будет конкатенация. Если будут разные типы, то там уже зависит от ситуации.

Причём в статических языках, опять же, ad-hoc полиморфизм реализуется за счёт перегрузки функций (то есть описываются разные тела функций, в которых задаются разные типы аргументов) и соответственно компилятор сам выбирает какую функцию в какой момент использовать. Внутри нет никаких if’ов, то есть мы уже работаем конкретно с теми типами, которые мы определили в данной функции. Под одним именем одной операции скрывается несколько разных тел.

В динамических языках мы этого делать не можем, поэтому там по сути всегда это сводится к тому, что у вас есть одна функция, внутри которой много if’ов, которые проверяют типы аргументов.

Например, если посмотреть исходники console.log, можно увидеть, что там это примерно так и устроено. Там используется функция формат, которая внутри проверяет типы аргументов и в зависимости от типа делает какие-то разные действия.

Полиморфизм подтипов

Напомню, что полиморфизм подтипов в объектно-ориентированных языках называют просто полиморфизм, что не совсем корректно.

Как раз этот полиморфизм позволяет вызывать РАЗНЫЙ код для РАЗНЫХ иерархий типов.

const obj = new SimpleCard(); // or PercentCard()
obj.damage(health);

Собственно, с этим полиморфизмом мы сквозь весь наш курс в первую очередь и знакомились и использовали его в нашей программе. И именно задача нашего курса была завести внутри языка полиморфизм подтипов.

Полиморфизм подтипов является ключевой штукой для ООП.

Почему это нужно – мы уже прекрасно знаем. Бывает, что для разных типов нужно вызывать разную реализацию одних и тех же (с точки зрения интерфейса) функций для того, чтобы не писать if. Это как раз к вопросу о том, что эта штука исключительно просто сокращает код с точки зрения практики, а формально вы, конечно, можете работать и без него.

Итоги

Полиморфизм связан с динамической диспетчеризацией, которую мы разбирали. Просто динамическая диспетчеризация – это один из способов реализации полиморфизма.

Любой язык и любая штука, с которой мы работаем, позволяет нам использовать полиморфизм и как раз с помощью динамической диспетчеризации мы можем его, собственно, реализовать и таким образом просто сокращать тот код, который мы пишем.


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты.

Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
900
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 130 курсов, 2000+ часов теории
  • 900 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff

Используйте Хекслет по максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы соглашаетесь c «Политикой конфиденциальности» и «Условиями оказания услуг»