Ну, прикол в том, что когда мы делаем центром нашего мышления обьекты и обмен сообщениями между ними, то когда мы описываем наш обьект, и пишем методы к нему, мы начинаем мыслить так, что то, что попадает к нам как сообщение, не такое важное, как то, что есть мы
В итоге метод-функция выглядит как (Наш обьект) - (Что-то другое, не такое крутое) -> наш ответ.
И когда мы пишем функцию add для нашего обьекта "{}" мы думаем, что нам приходит какая-то хуйня, и в итоге возвращаем тоже какую-то хуйню. В итоге {} + [] = 0
А потом мы пишем функцию add для обьекта "[]" и нам приходит что-то другое, ну мы вернем ему что-то, например "[object Object]"
А когда ты мыслишь функциями, ты понимаешь, что есть функция add, она должна принять два значения, и выдать что-то вразумительное на основании двух обьектов, а не только своего.
И поэтому в ФП юзают типы суммы, которые равноправно представляют свои конструкторы. А в ООП юзают наследование, которое бесконечно падает вниз твоя иерархическую структуру.