LINUX.ORG.RU

Понять суть правильного наследования в js

 ,


0

2

Много где читал (вот например https://medium.com/javascript-scene/common-misconceptions-about-inheritance-i... ) что классическое наследование (используя class, либо даже использую прототипы в js в стиле С++) это отстой - а возможности js (Object.assign нескольких базовых объектов в один, если я правильно понял) гораздо круче - но аргументы мне не очень понятны - они описывают проблемы которые я особо не испытывал (Про банан и гориллу). Либо просто говорят что все херня - юзай вот так.

Может я просто не правильно их понимаю - они не приводили примеров (кроме просто как использовать на примере животное -> собака - но там совсем не ясно, а в чем же преимущество) - может кто из вас показать пример (желательно решение реальной задачи) используя особенности js который написать на классическом (скажем java) языке было бы трудно либо не красиво либо код получился бы не качественный.

На работе я сейчас пишу достаточно большой проект - но 99% моего использовать классов это реакт - class Name extends from React.Component кроме этого есть всего два класса - DnD - класс который управляет драг енд дропом - изначально я его писал в Реакт классе - но когда все разрослось - вынес все что с ним связанно в отдельный класс - и связал с бывшим классом реакта.

Также есть класс SelectedStructure - нужна для удобной работы с хранением выбранных карточек - есть кнопка выбрать все - даже еще не загруженные заранее (есть скролл лоадер) Он используется только в DnD классе (могу выделить какие-то карточки - потом применить к ним DnD) например метод SelectedStructure

add(newItemId) {
    if (this.isNowSelectAllMode) {
         array.remove(newItemId) // храним всех кого не выбрали (все остальные выбраны из-за кнопки select All) 
                                 // значит при выборе элемента - мы из массива его на самом деле удаляем
    } else {
        array.push(newItemId)    // обычный режим - просто добавляем
    }
}

Так вот - я не испытал необходимости в тех вещах про которые рассказывают в статье - наверное я не понял их. П.С. писал какое-то время на java - базовые вещи понимаю - наследование использовал. на js пишу много и давно.

★★★

Последнее исправление: abs (всего исправлений: 1)

Ответ на: комментарий от e1nste1n

В чем вопрос-то?

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

abs ★★★
() автор топика

Как бы суть в том, что прототипированием описать объекты в скрипте намного проще, чем классами. Меньше кода и почти никакого проигрыша по производительности. То бишь - что позволено бякенду, роскошь и чрезмерное усложнение для фронтенда. Сами примеры не важны - важно окружение.Сам принцип - https://en.wikipedia.org/wiki/Prototype_pattern

anonymous
()
Ответ на: комментарий от abs

Понять суть правильного наследования в js

теория http://www.selflanguage.org/_static/published/self-power.pdf

Стать более лучшим разработчиком на js. Писать быстрее, с меньшим количеством багов, гибче, корректнее, понятнее.

+ практика

e1nste1n ★★★★★
()
Ответ на: комментарий от e1nste1n

+ практика

Дак как мне эту практику получить - если я использую мимикрию(закос) под классическое наследование (class Name extend BaseClass)

А как применить не классическое чтоб получить выгоду - не вижу.

Что я понял из статей которые читал - это возможность использовать assing от множество объектов - что-то типа решение проблемы ромбовидного наследования когда мы явно указываем от кого будет получено свойство если оно есть в обоих базовых объектов-классов.

Но опять же - я как-то не увидел причины этого использовать - в моем примере с DnD где я мог бы потенциально отнаследовать (assign) свой объект одновременно от Реакта, и от DnD я благополучно заменил композицией (В реакт классе есть экземпляр DnD)

А если я таки сделаю assign как мне потом это все интегрировать в экосистему реакта - он ведь ожидает класс

abs ★★★
() автор топика
Ответ на: комментарий от abs

он ведь ожидает класс

Э? Он ожидает функцию с определённым prototype, не более.

Хотя композиция лучше наследования, включая ромбовидные костыли.

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Э? Он ожидает функцию с определённым prototype, не более.

А, ну это норм тогда. Но все равно же - не просто функцию(чтоб вызвать ее) а получается функцию чтоб вызвать у нее метод render, да и другие live-тайм методы.

И получится что чтоб это все в свой объект - даже через assign добавить придется написать что-то типа

let akaReactClass = Object.assign({}, React.Component, new DnD(), {
    render: function() {
       return <div> {this.getSomeInfoFromDnD()} </div>
    },
    doSomeMyStuff: () => alert('haskell erlang closure');
    componentWillMount: function() {
       this.doSomeMyStuff();
    }
}

abs ★★★
() автор топика
Последнее исправление: abs (всего исправлений: 1)

если бы таковые преимущества существовали, прототипное наследование тут же подтянули во все мейнстримные языки бекэнда: шарп, питон, руби, да даже в жавку с плюсами

но нет

на деле, прототипное наследование — просто чуть хуже читаемая, но чуть более простая для записи альтернатива обычному

next_time ★★★★★
()

Ну основной смысл в том, что в жабаскрипте нема приватных методов, и каждый последующий «класс» может только добавить новые и перекрыть старые.

Хотя в es6 через Symbol можно приватных методов накостылять, но синтаксис так себе.

Еще через class можно только функции определять, константы (числа, строки) не выйдет. Их только через prototype.

IMHO нет смысла сильно париться на эту тему, пиши как тебе удобно.

Vit ★★★★★
()

с js не особо дружу. несколько раз пытался осилить статьи про «правильное» наследование в js. Типа определяете функцию, заполняете у нее прототип, потом у этого прототипа через какое-то магическое свойство с подчёркиваниями определяете следующий прототип. но если не хотите в этом разбираться, то берете другую готовую магическую функцию из 5 строк, которая за вас все сделает, но чтобы ее раскурить, нужно познать дзен.

По мне, так это какой-то треш и угар.

С es6 появились нормальные классы, которые похожи на классы в других языках. Да, по сравнению с другими языками у них куцая функциональность, да, типо, они являются лишь сахаром поверх того изначального треша, но по мне, лучше их использовать и не ломать голову, как оно внутри устроено. Если будет конкретная задача (скорее всего при взаимодействии с кривым сторонним кодом, написанным на старых прототипах), то там и надо разбираться.

anonymous
()
Ответ на: комментарий от Vit

Еще через class можно только функции определять, константы (числа, строки) не выйдет. Их только через prototype.

Можно члены с данными инициализировать как минимум из конструктора.

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

anonymous
()
Ответ на: комментарий от anonymous

Можно члены с данными инициализировать как минимум из конструктора.

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

Я плохо помню синтаксис, но скорее всего можно инициализировать и прям при описании класса

Ну вот начнешь делать реальный код - увидишь. Я ж не просто так пишу.

Еще через класс нельзя обернутые функции определять. Аналог My.prototype.foo = bluebird.coroutine(function () { ... }). Пока не было родного async/await, это сильно напрягало. Правда я в итоге все равно в константы упёрся, но это уже не так критично.

Vit ★★★★★
()
Ответ на: комментарий от Vit

Еще через class можно только функции определять, константы (числа, строки) не выйдет

class jsClass {
   a = 5
   myMethod() {
      console.log(a) // будет работать, у меня babel
   }
}
abs ★★★
() автор топика
Последнее исправление: abs (всего исправлений: 1)
Ответ на: комментарий от anonymous

несколько раз пытался осилить статьи про «правильное» наследование в js. Типа определяете функцию, заполняете у нее прототип,

Не - это типа используя прототипы косить под классическое наследования - в статье как раз говорится что это не правильно - типа убирает все плюсы которые есть в js.

abs ★★★
() автор топика
Ответ на: комментарий от Vit

в жабаскрипте нема приватных методов

Есть же.

const foo = () => {
  const privateMethod = () => 42;
  return {
    publicMethod() {
      return privateMethod() * 2;
    }
  };
}

protected нет, но они и не нужны.

x3al ★★★★★
()

Нехотел вбрасывать раньше времени

ответ на твой вопрос

суть правильного наследования в js

вот тут
https://github.com/danilw/cputests

смотри результаты кода «render» (и сам код), вот в этом вся суть(в скорости, если не понял, в js не существует правильного наследования), у меня есть объяснение этого ... но вкину потом в своем посте к проекту

через недельку вкину более подробное объяснение с небольшой статьей по всему пректу, через недельку добавлю еще один тест(или пару) для полноты картины

anonymous
()
Ответ на: комментарий от anonymous

в скорости

На фронте на скорость js плевать - чаще всего бутылочное горлышко будет в каком-то там css или еще где-то подальше от js.

abs ★★★
() автор топика
Ответ на: комментарий от abs

Дык суть не меняется, проблема со значением все равно останется - ты его сможешь проставить только в конструкторе и миксовать потом не выйдет. А через прототипы такую константу объявить вполне можно.

Я сейчас не касаюсь того, правильно так писать или нет, просто объясняю ограничение конструкции class. Плюсы у нее тоже есть - запись удобная.

Vit ★★★★★
()
Ответ на: комментарий от x3al

Не, ну я о родных инструментах, а не жутких эмуляциях через костыли.

То что ты описал сейчас можно сделать проще, через Symbol, но всё равно это как-то не эстетично выглядит.

Vit ★★★★★
()
Ответ на: комментарий от anonymous

Там на render какие-то подозрительные цифры для JS. На деоптимизации смахивает. Пока они есть, бенчмаркать бесполезно.

В среднем по больнице у целочисленных молотилок есть смысл ориентироваться на разницу в 1.5 раза между JS и C. Если разница в 4 раза и больше - значит что-то случилось.

Vit ★★★★★
()
Ответ на: комментарий от abs

Не должно работать, даже babel не поможет, если только ты не задействовал некий плагин от Васяна.

Задай себе вопрос, что такое a в методе myMethod? Переменная к которой обращаются по имени должна быть в скоупе, но там её нет, значит обращение идёт к global.a (или window.a).

surefire ★★★
()
Ответ на: комментарий от surefire

Продолжение...

Babel транспилирует твой пример только при включенном stage-2.

Но как я и предположил, он посадил a = 5 в constructor, как this.a = 5.

Разбирайся со скоупом, для понимания js это фундамент.

surefire ★★★
()
Ответ на: комментарий от surefire

Но как я и предположил, он посадил a = 5 в constructor, как this.a = 5.

Черт, да, там this.a - я опечатался. Но именно это и удобно. Я часто использую это в реактовых классах для начального state - а конструктор вообще не пишу.

После этого this.state работает как если бы и в конструкторе сделал

abs ★★★
() автор топика
Ответ на: комментарий от anonymous

правильного наследования

oh lol

anonymous
()
Ответ на: комментарий от surefire

Переменная к которой обращаются по имени должна быть в скоупе, но там её нет, значит обращение идёт к global.a (или window.a).

Нет. Тело класса всегда в strict mode.

Ну и у него static property.

x3al ★★★★★
()
Последнее исправление: x3al (всего исправлений: 1)
Ответ на: комментарий от x3al

Ну и у него static property.

Да не, там не статик - у каждого экземпляра своя собственная переменная - доступная через this

abs ★★★
() автор топика
Ответ на: комментарий от abs

Я похоже невнимательно ответ прочитал. Вот о чем шла речь:

// Через class такое не объявить (простое значение):
MyClass.prototype.foo = 5;

// и такое тоже (обертка):
MyClass.prototype.bar = bluebird.coroutine(function* () { ... })

Vit ★★★★★
()
Ответ на: комментарий от Vit

// Через class такое не объявить (простое значение):
MyClass.prototype.foo =

Я так понимаю это нужно для того чтоб потом использовать так

class myClass {
   printFoo() {
      console.log(this.foo)
   }
}
myClass.prototype.foo = 10
let a = new MyClass()
let b = new MyClass()
b.printFoo()

Но в чем минус использовать вместо этого статическое свойство?

abs ★★★
() автор топика
Ответ на: комментарий от x3al

Нет.

в общем суть в том, что при обращении к переменной по имени она ищется скоупе (во всех порождающих замыканиях), ни о каком из видов члена класса речи идти не может.

surefire ★★★
()
Ответ на: комментарий от abs

На всякий случай напоминаю, что я просто описал нюансы class, которые надо знать чтобы не напороться. И не давал ни каких рекомендаций что есть правильно а что нет.

Но в чем минус использовать вместо этого статическое свойство?

Дык гиморнее, если фабрику классов надо сделать. Хочется же единообразной обработки. А вообще можно прямо в конструкторе хоть все методы пришпиливать, технически это тоже будет работать.

https://github.com/nodeca/idoit/tree/master/lib - вот тут глянь *_template.js. Это шаблоны, по которым делаются кастомные классы с нужными пресетами, из которых потом делаются инстансы тасков :). Возможно это стоило как-то поприличнее сделать, но я не сообразил как. Просто в один прекрасный момент решил переписать этот код на модные классы, и теперь могу делиться результатами квеста :).

Vit ★★★★★
()

Как я понял, тебе советую юзать композицию вместо наследования. Что это и в чем преимущества: любой портал про ООП

mersinvald ★★★★★
()
Ответ на: комментарий от Vit

Дык гиморнее, если фабрику классов надо сделать. Хочется же единообразной обработки. А вообще можно прямо в конструкторе хоть все методы пришпиливать, технически это тоже будет работать.

Ну, если следовать принципам всегда в конструкторе дочернего класса вызвать при помощи super конструктор базового класса, то особой разницы где описывать методы в конструкторе или в описании классов/прототипах нет. если пользоваться классами из es6, то описание в теле класса выглядит логичнее, симпатичнее и правильнее, но в конструкторе можно навернуть больше логики и добавлять в объект нужные методы, в зависимости от параметров конструктора. хотя это является ересью.

anonymous
()
Ответ на: комментарий от anonymous

Я какбэ не против канонических классов и наследований с цепочками конструкторов. Просто с примесями иногда проще получается, хотя дело вкуса конечно.

Пример я по ссылке давал. Юзеру ради каждого типа таска городить новый класс просто гиморно. Если не влом вникать - апи в readme расписано, получилось просто и удобно.

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

Vit ★★★★★
()
Последнее исправление: Vit (всего исправлений: 1)
Ответ на: комментарий от mersinvald

Как я понял, тебе советую юзать композицию вместо наследования.

Нет.

abs ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.