Дополнительные параметры промежуточной функции документа

Существует ли правильный синтаксис для документирования необязательных параметров JavaScript, где необязательный параметр находится в середине заголовка функции (например, jQuery, Gulp и т. д.)

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

Пример:

/**
 * @param {number} a_num
 * @param {string} [a_str='']
 * @param {{}} a_obj
 */
function (a_num, a_str, a_obj) {
    if (!a_obj) a_obj = a_str; // doesn't want me to save a string to an object.
    a_str = '';
    // more stuff
}

Если это имеет значение, я использую PHPStorm от JetBrains, который использует стиль документов Google Closure (в основном). Хотя я ищу более общий, передовой подход.

Я подозреваю, что мог бы сделать что-то уродливое, например:

/**
 * @param {number} a_num
 * @param {string|{}} a_str
 * @param {{}} [a_obj=null]
 */

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


person samanime    schedule 09.02.2015    source источник
comment
У меня есть два голоса против и одна попытка закрыть за неясность. Я понимаю, что необязательные параметры в середине заголовка функции запрещены (или совершенно невозможны) в большинстве языков, но в JavaScript это допустимый и часто используемый шаблон, поэтому я думаю, что это правильный вопрос. Что касается неясности, если кто-то может оставить комментарий, сообщающий мне, что неясно, я был бы рад обновить вопрос. Спасибо.   -  person samanime    schedule 10.02.2015
comment
Есть много вещей, которые вы можете сделать в javascript, но только потому, что язык позволяет это, не означает, что это хорошая практика. Например, javascript допускает глобальные переменные, в то время как многие языки этого не делают, но это не означает, что использование большого количества глобальных переменных в JS является хорошей идеей.   -  person bhspencer    schedule 10.02.2015
comment
Я удалил свой ответ, так как он на самом деле не отвечает на ваш вопрос, но я добавляю его здесь в качестве комментария, поскольку я думаю, что это все еще актуальная часть разговора: я считаю плохой практикой помещать необязательные параметры в середину параметра список. Это может запутать пользователей вашего API. Вместо этого подумайте о том, чтобы либо поместить необязательный параметр в конец параметров, либо передать объект параметров, а не список параметров.   -  person bhspencer    schedule 11.02.2015
comment
@bhspencer: Достаточно справедливо, и я тоже не совсем с вами не согласен. Я думаю, что единственный допустимый вариант использования, в котором это помогает внести ясность, — это когда последним параметром является обратный вызов, который позволяет передавать более чистые и легкие для чтения анонимные функции. Спасибо.   -  person samanime    schedule 11.02.2015
comment
Я бы вообще не рекомендовал использовать анонимные функции. Я в основном разделяю эти мнения Тодда Мотто toddmotto.com/avoiding-anonymous-javascript-functions   -  person bhspencer    schedule 11.02.2015
comment
@bhspencer Я тоже с этим в основном согласен. Однако есть допустимое время и место для анонимных обратных вызовов. Конкретный пример, о котором я думаю, который также является вариантом использования функции, о которой я задал этот вопрос, относится к функции, используемой в задаче gulp. Задачи Gulp, как правило, просты, и эту функцию никогда не нужно будет использовать повторно. Использование обратных вызовов в этом сценарии улучшает читабельность.   -  person samanime    schedule 11.02.2015


Ответы (1)


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

  1. Javascript на самом деле не поддерживает необязательные параметры в середине списка аргументов функции (для этого вам нужны именованные параметры). Вместо этого функции, которые объявляют об этом, пытаются определить, какая версия функции была вызвана, основываясь на количестве и значениях параметров.

  2. Javascript также не поддерживает перегрузку функций.

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

В качестве примера возьмем одну из подписей jQuery.prototype.bind. :

jQuery.prototype.bind( eventType [, eventData ], handler )

Мы признаем, что для документирования этого метода всегда требуются два параметра. Сначала давайте переставим и переименуем параметры:

jQuery.prototype.bind( eventType, eventDataOrHandler, [ handler ] )

С этой перестановкой JSDoc становится понятнее:

/**
 * @param {string} eventType
 * @param {(*|function(Event))} eventDataOrHandler
 * @param {function(Event)=} handler
 * @return {!jQuery}
 */
jQuery.prototype.bind =
    function(eventType, eventDataOrHandler, handler) {};

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

Просмотр внешних элементов jQuery компилятора Closure даст вам множество примеров.

person Chad Killingsworth    schedule 12.02.2015
comment
Спасибо. Примерно так я уже и подумал. Надеялся на что-то более волшебное, но имеет смысл. К счастью, я документирую только одну функцию, так что ничего страшного. - person samanime; 13.02.2015
comment
@doc Я почти уверен, что людям не нравится идея моего вопроса, и у них возникают проблемы с тем, чтобы отличить недовольство содержанием вопроса (и ответа) от плохо написанного вопроса. - person samanime; 18.02.2015