Разделение большого класса на модули
Я пытаюсь построить свою первую библиотеку (браузер) и решил использовать модули commonjs в стиле узла + browserify для организации моего кода. Я структурировал его таким образом, что каждый модуль содержит 1 класс, который работал довольно хорошо, пока некоторые из классов не начали становиться невероятно огромными.
Итак, у меня есть класс, подобный
module.exports = MyClass;
function MyClass() {
//initializing stuff
this.publiceMethod= function publicMethod() {
//do stuff
};
var privateMethod = function privateMethod() {
//do stuff
};
}
MyClass.prototype.notSureMethod = function notSureMethod() {
//err... static method?
}
Проблема в том, что у меня есть большое количество методов, использующих различные способы их объявления ( this.method
, var method
, this.prototype.method
). Что я такое интересно, есть ли относительно простой способ создать другой модуль (Ы) и потребовать их в MyClass
как часть определения класса для повышения читаемости.
Идеальное поведение, которое я ищу, - это что-то вроде модуля, который является самоисполняющейся функцией, которая разделяет ту же область, из которой она вызывается (включая частные переменные / методы, если это возможно).
Я изучаю JS всего несколько недель, так что будьте со мной помягче, если я веду себя как идиот. Спасибо заранее :)-- edit--
Слепо играя с ним, я понял, как сделать то, что я ищу, с помощью прототипов и общедоступных методов.//Underneath MyClass definition
require('./prototype-methods')(MyClass);
require('./public-methods')(MyClass);
Тогда суть его в других файлах такова:
module.exports = function(MyClass) {
MyClass.prototype.method = . . . .
MyClass.method = . . . .
}
Таким образом, это заставляет меня задуматься, есть ли способ сделать что-то подобное с частными методами. Есть идеи?
- - - edit2 - - -
Что именно вы используете? Не могли бы вы привести пример того, что ваш класс неужели?
Я создаю библиотеку для Web audio api, которая, по сути, позволяет вам сочинять музыку. У меня есть пространство имен для библиотеки, и пространство имен (в данный момент) содержит несколько различных классов. Существует класс score
, который выступает посредником между part
, effect
и player
классы. Класс part
- это просто оболочка для объекта instrument
, который является объектом с функциями, воспроизводящими музыку.
Пространство имен имеет фабричную функцию, которая возвращает новый экземпляр score
, которая в свою очередь имеет заводские функции, возвращающие новые part
(s), effect
(s) и в конечном итоге player
. Кроме того, в любой момент времени может быть больше 1 балла, поэтому я потенциально могу сделать плейлист.
part
. Я хочу, чтобы библиотека была очень гибкой в том, какие обозначения она принимает, поэтому мне нужно было добавить довольно много методов для учета всех этих обозначений (= big file).3 ответа:
Я обнаружил, что могу в значительной степени добавить все, кроме частных членов, в
MyClass
с модулем, передавMyClass
модулю в качестве параметра.Кажется, что я мог бы технически добавить / получить доступ к закрытым членам, используя
eval
, но мне сказали, что это зло. Просто вынимание прототипа и открытых методов из файла значительно урезало его, так что оставление закрытых членов в нем совершенно нормально.
Isbn 978-0-596-80675-0 (Глава 5 Шаблоны Создания Объектов / Шаблон Песочницы), isbn 0-596-10199-6 (Глава 10 модули и пространства имен / утилиты модулей)
На данный момент я также нахожусь в поиске удобного метода создания приватных данных. В настоящее время я использую функциональный шаблон наследования и defineClass следующим образом:
var defineClass = function () { var inheritance = function inheritance() { }; return function defineClass(data) { var classname = data.name, superclass = data.extend || Object, constructor = data.construct || function () { }, methods = data.methods || {}, statics = data.statics || {}, borrows, provides; if (!data.borrows) { borrows = []; } else { if (data.borrows instanceof Array) { borrows = data.borrows; } else { borrows = [data.borrows]; }; }; if (!data.provides) { provides = []; } else { if (data.provides instanceof Array) { provides = data.provides; } else { provides = [data.provides]; }; }; inheritance.prototype = superclass.prototype; var proto = new inheritance(); for (var i = 0; i < borrows.length; i++) { var c = borrows[i]; for (var p in c.prototype) { if (typeof c.prototype[p] != "function") continue; proto[p] = c.prototype[p]; } } for (var p in methods) { proto[p] = methods[p]; }; proto.constructor = constructor; constructor.superclass = superclass.prototype; if (classname) { proto.classname = classname; }; for (var i = 0; i < provides.length; i++) { var c = provides[i]; for (var p in c.prototype) { if (typeof c.prototype[p] != "function") { continue; }; if (p == "constructor" || p == "superclass") { continue; }; if (p in proto && typeof proto[p] == "function" && proto[p].length == c.prototype[p].length) { continue; }; throw new Error("Class " + classname + " are not provided method " + c.classname + "." + p); }; }; constructor.prototype = proto; for (var p in statics) { constructor[p] = statics[p]; }; return constructor; } }(); //SAMPLE CODE var tempObj = function () { }; // example of a variable tempObj.prototype.distance = 0; // example of a method tempObj.prototype.walk = function (time) { this.distance = this.distance + time * this.walkSpeed }; tempObj.prototype.toString = function () { return this.name + " distance " + this.distance }; var Animal = defineClass({ name: "Animal", construct: function (name, walkSpeed) { this.name = name; this.walkSpeed = walkSpeed; }, borrows: tempObj, methods: { distance: tempObj.prototype.distance } }); var tempObj2 = defineClass({ methods: { fly: function (time) { this.distance = this.distance + time * this.flySpeed } } }); var Bird = defineClass({ name: "Bird", construct: function (name, walkSpeed, flySpeed) { // call the parent constructor Bird.superclass.constructor.call(this, name, walkSpeed) this.flySpeed = flySpeed }, extend: Animal, borrows: tempObj2 }); var Cuckoo = defineClass({ name: "Cuckoo", extend: Bird, construct: function (name, walkSpeed, flySpeed) { // call the parent constructor Cuckoo.superclass.constructor.call(this, name, walkSpeed, flySpeed) this.word = "cucoo"; }, methods: { say: function () { return this.name + " says " + this.word; } } }); var animal = new Animal("Dog", 2); animal.walk(3); var dd = animal.toString(); // => Dog distance 6 bird = new Bird("Bird", 1, 10); bird.walk(3); var ww = bird.toString(); // => Bird distance 3 bird.fly(2); var ff = bird.toString(); // => Bird distance 23 cuckoo = new Cuckoo("Cuckoo", 1, 10); cuckoo.walk(3); var ww = cuckoo.toString(); // => Cuckoo distance 3 cuckoo.fly(2); var ff = cuckoo.toString(); // => Cuckoo distance 23 var cSay = cuckoo.say(); // => Cuckoo says cucoo
Что именно вы используете? Не могли бы вы привести пример того, что делает ваш класс?
Потому что идти объектно-ориентированным путем не всегда лучший способ делать вещи в JavaScript. Модули в стиле узлов и тот факт, что функции являются первоклассными гражданами в js, действительно облегчают функциональный путь. Это означает, что вы можете экспортировать отдельные функции, которые делают ровно одну вещь. Например:
module.exports = function(x, y) { return x * y }
И во втором модуле вы можете использовать такую функцию, как это:
var add = require('./add.js') var result = add(15, 23);
Если вы хотите узнать больше об этом, проверьте Этот СЕМИНАР nodeschool.