Лучшие практики для «абстрактных» функций в JavaScript? - PullRequest
19 голосов
/ 20 сентября 2011

Я только что написал некоторый код 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, чтобы функция этогообъект может быть определен позже?

Ответы [ 5 ]

21 голосов
/ 20 сентября 2011

Только не определяйте функцию.

Javascript - это тип * утка .Если это похоже на утку и крякает как утка, то это утка.
Вам не нужно делать ничего особенного, чтобы сделать эту работу;до тех пор, пока функция существует, когда вы вызываете ее, она будет работать нормально.

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

9 голосов
/ 20 сентября 2011

Я согласен с 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";
},

2019 Обновление

Используйте TypeScript, если можете Объявление абстрактного метода в TypeScript

7 голосов
/ 25 февраля 2013

По мере того, как наша команда растет, а наш проект javascript становится все более сложным, мы также должны начать реализовывать функции ОО.

В нашем «абстрактном» методе javascript мы просто выкидываем ошибку или выводим предупреждение.Это пример из нашего объекта Page:

Page.initialLoad = function() { //abstract
    alert('Page.initialLoad not implemented');
};

В мире Java это аналогично:

public void abstract initialLoad();

Java-код дает время компиляции ошибка,однако в Javascript мы получили бы ошибка времени выполнения .(грязное диалоговое окно с сообщением о том, что реализующий объект еще не реализовал этот метод).

У нас есть несколько разрозненных команд, которые используют объект Page;философия «типизирования утки» абсолютно не подходит нам.Без этих псевдо-абстрактных методов у нас, как правило, отсутствует связь по API, и иногда мы получаем саботаж над суперобъектом (т. Е. Потому, что пользователь понятия не имеет, что он должен реализовывать метод).

IЯ устал от этой философии «типизирования утки».Я не уверен, что сторонники когда-либо были в сложном проекте Javascript с более чем 10 разработчиками.

3 голосов
/ 20 сентября 2011

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

Да, 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 не всегда поддерживается (старые браузеры и т. Д.),Старый (и некоторые могут сказать, нормальный ) способ сделать что-то - это с помощью прикольного оператора new (не думайте слишком много об имени - его путаница с целью отвлечьJava люди)

function Constructor(arg){
    this.x = arg;
}

Constructor.prototype = {
    f: function(){ ... }
};

var obj = new Constructor(17);
obj.f();

Важным отличием, которое следует учитывать при использовании прототипов наследования, является отсутствие закрытых переменных. Только наследуемые переменные могут быть унаследованы! Из-за этого распространенным соглашением является использование подчеркивания в качестве префикса для закрытых и защищенных переменных.

0 голосов
/ 20 сентября 2011

Возможно, вы захотите взглянуть на этот предыдущий пост Как создать абстрактный базовый класс в JavaScript?

Всего несколько сайтов для небольшого чтения для вас на ООП и JavaScript, я предполагаю, что вы новичок в JavaScript как язык ООП на основе комментария, который вы сказали

http://mckoss.com/jscript/object.htm

http://www.codeproject.com/KB/aspnet/JsOOP1.aspx

http://www.javascriptkit.com/javatutors/oopjs.shtml

...