В чем цель полиморфизма?
Полиморфизм делает систему статических типов более гибкой без потери (значительной) безопасности статических типов за счет ослабления условий эквивалентности типов. Остается доказательство того, что программа будет работать только в том случае, если она не содержит ошибок типа.
Полиморфная функция или тип данных является более общим, чем мономорфный, потому что он может использоваться в более широком диапазоне сценариев. В этом смысле полиморфизм представляет собой идею обобщения в строго типизированных языках.
Как это применимо к Javascript?
Javascript имеет слабую систему динамических типов. Такая система типов эквивалентна строгой системе типов, содержащей только один тип. Мы можем думать о таком типе как о типе огромного объединения (псевдосинтаксис):
type T =
| Undefined
| Null
| Number
| String
| Boolean
| Symbol
| Object
| Array
| Map
| ...
Каждое значение будет связано с одним из этих альтернативных типов во время выполнения. А поскольку Javascript слабо типизирован, каждое значение может изменять свой тип любое количество раз.
Если мы возьмем теоретическую перспективу и примем во внимание, что существует только один тип, мы можем с уверенностью сказать, что система типов Javascript не имеет понятия полиморфизма. Вместо этого у нас есть утиная типизация и неявное приведение типов.
Но это не должно мешать нам думать о типах в наших программах. Из-за отсутствия типов в Javascript нам необходимо вывести их в процессе кодирования. Наш разум должен заменить отсутствующий компилятор, то есть, как только мы смотрим на программу, мы должны распознавать не только алгоритмы, но и лежащие в основе (возможно, полиморфные) типы. Эти типы помогут нам создавать более надежные и устойчивые программы.
Чтобы сделать это правильно, я собираюсь дать вам обзор наиболее распространенных проявлений полиморфизма.
Параметрический полиморфизм (он же дженерики)
Параметрический полиморфизм говорит о том, что разные типы взаимозаменяемы, потому что типы вообще не имеют значения. Функция, определяющая один или несколько параметров параметрического полиморфного типа, не должна ничего знать о соответствующих аргументах, но обрабатывать их все одинаково, поскольку они могут адаптироваться к любому типу. Это довольно ограничивает, потому что такая функция может работать только с теми свойствами своих аргументов, которые не являются частью их данных:
const id = x => x;
id(1);
id("foo");
const k = x => y => x;
const k_ = x => y => y;
k(1) ("foo");
k_(1) ("foo");
const append = x => xs => xs.concat([x]);
append(3) ([1, 2]);
append("c") (["a", "b"]);
Специальный полиморфизм (он же перегрузка)
Специальный полиморфизм говорит, что разные типы эквивалентны только для определенной цели. Чтобы быть эквивалентным в этом смысле, тип должен реализовывать набор функций, специфичных для этой цели. Функция, которая определяет один или несколько параметров специального полиморфного типа, должна знать, какие наборы функций связаны с каждым из ее аргументов.
Специальный полиморфизм делает функцию совместимой с более крупной областью типов. Следующий пример иллюстрирует цель «сопоставления» и то, как типы могут реализовать это ограничение. Вместо набора функций "отображаемое" ограничение включает только одну map
функцию:
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();
}
};
const map = f => t => t.map(f, t);
const sqr = x => x * x;
const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();
console.log(
map(sqr) (xs)
);
console.log(
map(sqr) (x)
);
console.log(
map(sqr) (y)
);
Полиморфизм подтипа
Поскольку другие ответы уже охватывают полиморфизм подтипа, я пропускаю его.
Структурный полиморфизм (также известный как подтип strutrual)
Структурный полиморфизм говорит, что разные типы эквивалентны, если они содержат одну и ту же структуру таким образом, что один тип имеет все свойства другого, но может включать дополнительные свойства. При этом структурный полиморфизм - это утиная типизация во время компиляции и, безусловно, обеспечивает некоторую дополнительную безопасность типов. Но, утверждая, что два значения имеют один и тот же тип только потому, что они разделяют некоторые свойства, он полностью игнорирует семантический уровень значений:
const weight = {value: 90, foo: true};
const speed = {value: 90, foo: false, bar: [1, 2, 3]};
К сожалению, speed
это считается подтипом, weight
и как только мы сравниваем value
свойства, мы фактически сравниваем яблоки с апельсинами.