Как писать Толковый ООП код в JS?

Всем доброго времени. Понимаю что вопрос глубокий но хотелось бы понять как писать годный код в ооп. Прогаю относительно недавно и при освоении ооп который должен был упростить код(как часто говорят на харбре))) вытоге уже сума меня сводить начал. Хотелось бы понимание в верном направлении я рою или нагромаздил черти че. Вот пример кода реализуещего на основе localStorage имитацию файловой системы для редактора. к нему еще несколько подобных фалов прилагается
const ul = "ul";
const li = "li";
const explorerlist = "explorer-list";
const sublist = 'explorer-sublist-item';
const projects = "projects";
const $toolbar = $("<div>", {
    class: "explorer-toolbar"
});
$toolbar.append($("<button>", {
    class: "explorer-toolbar-btn material-icons",
    title: "Create file",
    "data-action": "file-new",
    html: 'insert_drive_file'
}));
$toolbar.append($("<button>", {
    class: "explorer-toolbar-btn material-icons",
    title: "Create folder",
    "data-action": "folder-new",
    html: 'create_new_folder'
}));
$toolbar.append($("<button>", {
    class: "explorer-toolbar-btn material-icons",
    title: "Collapse all folders",
    "data-action": "collapse-all",
    html: 'indeterminate_check_box'
}));
$title = $("<div>", {
    "class": "explorer-input-wrapper"
}).append($("<input>", {
    "class": "explorer-input-field isBlured",
    "type": 'text',
    "data-action": "project-name",
    "placeholder": "Project Name"
}));
class EXPLORER {
    constructor() {
        this.treeID = explorerlist;
        this.p = {};
        this.opened = {};
        this.init()
    }
    init() {
        let opened = Local.get("opened");
        this.opened["project"] = opened["project"] || 0;
        this.opened["files"] = opened.files || [];
        Local.set("opened", this.opened);
    }
    get projects() {
        var p = Local.get(projects);
        for (var key in p) {
            let n = p[key]["name"];
            this.p[n] = p[key]
        }
        return Local.get(projects);
    }
    get Project() {
        var _this = this;
        return new class {
            open(name) {
                $title.attr("data-id", name).val(name);
                for (let i = 0; i < _this.projects.length; i++) {
                    if (name == _this.projects[i].name) {
                        const dir = _this.projects[i].dir;
                        Local.setKey("opened", "project", i);
                        Tree.showTree(ul, li, sublist, Tree.generate(dir), _this.$filetree);
                    }
                }
            }
            get projects() {
                var p = Local.get(projects);
                for (var key in p) {
                    let n = p[key]["name"];
                    _this.p[n] = p[key]
                }
                return _this.p
            }
        };
    }
    get File() {
        var _this = this;
        return new class {
            open(name) {
                let filesArr = Local.getKey("opened", "files");
                _this.file_path = {};
                var dir = Local.get("projects")[_this.opened.project].dir;
                dir.reduce((q, files) => {
                    const _file = files.substring(files.indexOf("/") + 1);
                    _this.file_path[_file] = files
                }, _this.file_path);
                if (_this.opened["project"] !== "undefined") {
                    var code = Local.get("projects")[_this.opened.project].files[name];
                    Workspace.Editors(_this.file_path[name]).create(code[1], _this.file_path[name]);
                    Workspace.Editors(_this.file_path[name]).instance.setValue(code[0]);
                    filesArr.push(_this.file_path[name]);
                    Local.setKey("opened", "files", filesArr);
                }
            }
            close(name) {
                let filesArr = Local.getKey("opened", "files");
                for (var i = 0; i < filesArr.length; i++)
                    if (filesArr[i] === name) filesArr.splice(i, 1)
                Local.setKey("opened", "files", filesArr);
            }
        }
    }
    render() {
        this.$explorer = $("#explorer");
        this.$filetree = $("<ul>", {
            class: explorerlist,
            id: explorerlist
        });
        this.$explorer.append($toolbar, $title, this.$filetree);
        event(this.$filetree, this);
        for (let i = 0; i < this.projects.length; i++) {
            if (i == this.opened["project"]) {
                this.Project.open(this.projects[i]["name"]);
            }
        }
    }
}
var event = (elem, explorer) => {
    $(document).on('click touchend', elem, e => {
        if ($(e.target).parent('li').hasClass(sublist)) {
            $(e.target).parent('li').toggleClass('active');
        }
        if ($(e.target).parent('li').hasClass('explorer-file')) {
            let elem = e.target,
                str = '';
            if (!elem && elem === this.$filetree) return
            elem = $(e.target).parent().parent('li');
            let dir = elem ? elem.children().text() : '';
            str = `${str && dir ? `${dir}/` : dir}${str}`;
        }
    });
    $(document).on('dblclick touchend', elem, e => {
        if ($(e.target).parent().hasClass('explorer-file-item')) {
            var name = $(e.target).text();
            explorer.File.open(name);
        }
    });
    $(document).on("change", $title, (e) => {
        var projName = $(e.target).attr("data-id")
        var projects = EXPLORER.projects;
        for (var key in projects) {
            if (projects[key]["name"] == projName) {
                projects[key]["name"] = $(e.target).val();
                Local.set(projects, projects)
            }
        }
    });
}

function initMode(fileExtension) {
    switch (fileExtension) {
        case "html" || "xml":
            return "htmlmixed";
        case "js":
            return "javascript";
        case "css":
            return "css";
    }
}
function getFormat(text) {
    return text.split(".").pop()
}

Если есть какие статейки на примете подкиньте плз. Те что нашел на харбре и мозиле весьма примитивны и не дают понго представления приминения сих принципов на практике
  • Вопрос задан
  • 6988 просмотров
Пригласить эксперта
Ответы на вопрос 5
@MadridianFox
Web-программист, многостаночник
Понимание ООП приходит с опытом. Сначала надо написать много кода, самому заметить его недостатки и тогда перечитывая те же самые статейки вы начнёте по новому понимать, что вот конкретно эту штуку можно было бы использовать в том моём коде, и было бы лучше.

Я разделяю ООП на аутентичное и классическое. Аутентичное, это ООП как его представлял автор - объекты обмениваются сообщениями.
Классическое - это то как оно реализовано в Java.
И там и там есть инкапсуляция и полиморфизм. Наследование это приятная фишка классического ООП. Так же как и все пляски с типами. Вообще строгая типизация не является частью ООП. По крайней мере не является частью аутентичного ООП.

Поэтому переход на typescript позволит только более точно воспроизводить классическое ООП. Ну и проверку типов добавит. Это само по себе полезно, но для ООП никакого значения не имеет.

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

Заметьте, про js я почти ничего не сказал. Потому что дело не в нём. Дело только в понимании ООП. У языков программирования, конечно, есть различные возможности и ограничения что которые позволяют использовать ту или иную парадигму. Но ООП на js можно было делать и до es6, просто потому что в js можно инкапсулировать код в объект.

И ещё, когда мы начинаем делить код на объекты, необходим механизм разделения кода на файлы и собирания его обратно. Т.е. нужна модульность. Лучше всего, конечно, использовать webpack, но вроде как в js есть и другие системы. Не сборки, а именно подключения модулей.
Ответ написан
yurakostin
@yurakostin
Front-end developer
На мой вкус там, где ООП - там паттерны, а где паттерны - там не обязательно должно быть ООП.
Вы должны понимать, зачем вы создаёте все ваши классы. Какую проблему они решают.

Вот достаточно популярный ресурс по паттернам.

Если вы хотите прям ООП-ООП, то у вас более половины вашего кода должно быть написано иначе(а ещё лучше на ООП языке типа Java). Не должно быть просто вызовов функций: вся работа через объекты. Никаких `$toolbar.append` и прочего.

Опять же, я могу быть глубоко не прав, но js ни ООП, ни ФП подход не реализует в полной мере. Поэтому только и остаётся, что писать в каком-то гибридном стиле. Возможно, что это огромная проблема языка, возможно наоборот.
Ответ написан
Комментировать
@letMeDie
Не знаю что там по статейкам, но лучше переходи на Typescript.
Ответ написан
Комментировать
Ni55aN
@Ni55aN
1. Представление (работа с DOM) должно быть изолировано
2. return new class - не надо так
3. ... остальное проще рассматривать при решении предыдущих пунктов
Ответ написан
@777Polar_Fox777
JQuerry? Классы в JS? Кошмар. Лучше переходи на функции и React
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы