Рекомендации по "абстрактным" функциям в JavaScript?
Я просто написал код JavaScript, который следует вместе с тем, что я считаю хорошей практикой для создания объекта с закрытием и некоторыми функциями:
var myStuff = (function() {
var number = 0;
var fn = {};
fn.increment = function() { number++; };
fn.decrement = function() { number--; };
fn.getNumber = function() { return number; };
return fn;
})();
myStuff.increment();
myStuff.increment();
alert(myStuff.getNumber()); // alerts '2'
У меня нет проблем с написанием кода, как в предыдущем фрагменте. Я хотел бы написать код с функциональностью, подобной "абстрактному" классу ООП. Вот результат моих усилий:
var myStuff = (function () {
var number = 0;
var fn = {};
fn.increment = function () { number++; };
fn.decrement = function () { number--; };
fn.doSomethingCrazy = function () { throw new Error('not implemented'); }; // I want to specify later what this does.
fn.doSomethingCrazyTwice = function () { fn.doSomethingCrazy(); fn.doSomethingCrazy(); };
fn.getNumber = function () { return number; };
return fn;
})();
myStuff.doSomethingCrazy = function () { this.increment(); this.increment(); };
myStuff.doSomethingCrazyTwice();
alert(myStuff.getNumber()); // alerts '4'
Вышеприведенный фрагмент кода работает, но он не выглядит грациозным. Возможно, я пытаюсь заставить JavaScript (функциональный язык) делать то, для чего он не предназначен (наследование объектов)
Что такое хороший способ определить объект в JavaScript, чтобы функция этого объекта могла быть определена позже?
Ответы
Ответ 1
Просто не определяйте функцию.
Javascript - это утиный язык. Если это похоже на утку, и она уклоняется от утки, это утка.
Вам не нужно делать что-либо особенное для выполнения этой работы; пока функция существует, когда вы ее вызываете, она будет работать нормально.
Если вы вызываете его в экземпляре, который не имеет этой функции, вы получите сообщение об ошибке на call-сайте.
Ответ 2
Я согласен с SLaks, нет необходимости определять функцию, но я все равно склоняюсь к этому. Это потому, что для меня важная часть находится в документации. Когда кто-то читает мой класс, я хочу, чтобы было ясно, что вы должны реализовать эти методы, какие аргументы будут переданы и что должно быть возвращено.
Это из файла на работе. Было несколько реализаций функции с базовым классом, который выполнял загрузку данных с интервалами.
/**
* Called when data is received and should update the data buffer
* for each of the charts
*
* @abstract
* @param {cci.ads.Wave[]} waves
* @void
*/
updateChartsData: function(waves){
throw "Abstract method updateChartsData not implemented";
},
Ответ 3
По мере того, как наша команда растет, и наш проект javascript становится все более сложным, мы должны также начать реализовывать функции OO.
В нашем абстрактном методе javascript мы просто бросаем ошибку или выставляем предупреждение. Это пример из объекта Page:
Page.initialLoad = function() { //abstract
alert('Page.initialLoad not implemented');
};
В java-мире это аналогично:
public void abstract initialLoad();
Код Java дает время компиляции, однако в Javascript мы получаем ошибку времени выполнения. (грязное диалоговое окно с сообщением о том, что объект реализации еще не реализовал этот метод).
У нас есть несколько разрозненных команд, которые используют объект Page; философия "утиной печати" абсолютно не режет ее с нами. Без этих псевдо-абстрактных методов у нас вообще отсутствует связь API, и иногда мы получаем саботаж суперъекта (т.е. Потому что пользователь понятия не имеет, что они должны реализовывать метод).
Я устал от этой философии "утиной печати". Я не уверен, были ли сторонники когда-либо в сложном проекте Javascript с 10+ разработчиками.
Ответ 4
Если вы не найдете свой путь изящным, возможно, есть способ создать некоторые функции, чтобы упростить процесс, чтобы он выглядел лучше. Но вернемся к теме...
Да, Javascript имеет встроенное делегирование, а также наследование через прототипы.
Учитывая прототипный объект:
var proto = {
f: function(){ console.log(this.x); }
}
Мы можем создать новый объект, который наследует от него:
var obj = Object.create(proto);
obj.x = 42;
obj.f(); //should work!
for(var i in obj) console.log(i);
//should print x, f and some other stuff perhaps
Просто помните, что выполнение вещей непосредственно через Object.create не всегда поддерживается (старые браузеры и т.д.). Старый (и некоторые могут сказать, нормальный) способ делать вещи через фанк новый оператор (не слишком много думайте о названии - его запутывает с целью отвлечь людей Java)
function Constructor(arg){
this.x = arg;
}
Constructor.prototype = {
f: function(){ ... }
};
var obj = new Constructor(17);
obj.f();
Важное отличие от прототипического наследования заключается в отсутствии частных переменных. Наследуются только общедоступные переменные! Из-за этого общим соглашением является использование подчеркивания в качестве префикса для частных и защищенных переменных.
Ответ 5
Возможно, вам стоит взглянуть на предыдущий пост Как создать абстрактный базовый класс в JavaScript?
Просто несколько сайтов для некоторого легкого чтения для вас в ООП и JavaScript, я предполагаю, что ваш новый для JavaScript как OOP langauge на основе комментария, который вы сказали
http://mckoss.com/jscript/object.htm
http://www.codeproject.com/KB/aspnet/JsOOP1.aspx
http://www.javascriptkit.com/javatutors/oopjs.shtml