Вопрос из серии "почему в функциональных языках нет циклов и переменных и как с этим жить". Так вот, жить можно вполне хорошо. Просто немного по-другому.
Советую изучить, что же такое ООП и какое оно бывает. За пару минут можно найти инфу, что в жаваскрипте ООП - прототипное, а в питоне "классоориентированое". Т.е. в первом всё есть объект, и создавать новые объекты можно только клонируя основной объект, все методы и поля ищутся сперва у объекта, а потом у всех его прототипов. Во втором случае есть разделение на классы и объекты - экземпляры этих классов. Там диспетчеризация устроена по-другому: методы и поля ищутся у класса, а потом у всех его предков.
И обходиться без наследования и метаклассов можно довольно легко, если знать, для чего же вообще нужно наследование и метаклассы. Метакласс позволяет манипулировать создаваемым классом на уровне его создания. Т.е. в питоне есть 2 понятия: класс и его экземпляр. В конструкторе класса можно определить поведение создаваемых экземпляров (через __new__ и __init__). Чтобы изменить поведение самого класса (а не его экземпляра) и нужны метаклассы: там, в функциях __init__ и __new__ можно переопределить поведение при создании класса. Так как в жаваскрипте такого разделения нет, то и отпадает само понятие метакласса: каждый объект создаётся путём клонирования от базового объекта (Object в js, хотя можно клонировать и любой другой объект: Array, Function, твой собственный). Такая же фигня и для наследования: там ты просто указываешь, какие поля могут выступать в качестве прототипов для всех "дочерних" объектов, это когда пишешь MyClass.prototype.someMethod = function(args) { ... }. В данном случае, someMethod будет сперва искаться среди самого объекта. Если там такого нет, то ищется в прототипе, т.е. в MyClass. Ну "классы" там объявляются функциями, потому что синтаксис не предусматривает создание класса. Да и то, функция-класс - просто синтаксический сахар: при вызове оператора new MyClass эта функция исполняется и возвращает копию объекта Object, над которой применили некие операции (которые ты как раз и описываешь в ней). Для каждой функции создаётся свой локальный контекст, который хранится в переменной this. Ты можешь в функции-классе описать, какие поля добавить в this, и она вернёт тебе как раз-таки этот изменённый this. Вот в lua нет даже оператора new, и ничего, вполне удобное ООП.
У каждого подхода есть и плюсы и минусы. Мне удобно писать в обоих стилях. Единственное, могут возникнуть проблемы, когда в классе вытаешься присвоить полю какую-то функцию (callback). This внутри этого колбека будет иметь локальный контекст этой функции, а объекта, в котором находится это поле. На помощь приходит функция bind.
P.S. Важно понимать, что функции являются объектами (в обоих языках). Но в js использование функций как переменных встречается гораздо чаще. Поэтому, строго говоря, нет никаких методов и полей в js. У объекта просто есть члены, которые могут быть как простыми данными и объектами, так и функциями. Собственно, для питона это тоже верно, ведь сами классы тоже являются объектами (экземпляры типа type). Просто там есть 2 понятия, как бы двухуровневая система. Ну и там куда реже члену объекта присваивают функцию, нежели в JS.