Pull to refresh

Comments 18

А что мешает использовать именованные аргументы?
1. Если среди них есть необязательные, то при вызове придётся указаывать его как null например.
2. Невозможно использование 2х разных прототипов.
Как пример могу привести метод animate из jQuery API. Он изобилует необязательными аргументами и имеет 2 прототипа.

.animate( properties [, duration ] [, easing ] [, complete ] )
.animate( properties, options )
animate({
properties: blabla,
duration: 7,
easing: true,
complete: foo,
options: myopt
})
Любую строчку параметров можно опустить без всякого null, в этом случае там будет undefined:
animate({
properties: blabla,
duration: 7
})
И тем не менее авторы jQuery предусмотрели передачу duration, easing, complete через список аргументов, а не только в объекте свойств.
Значит это кому-то нужно, потому-что упрощает жизнь.
Предположу, что это проще для тех, кто пришёл с Си, понятнее выглядит при малом количестве параметров и позволяет экономить несколько символов в прикладном коде, но вынуждает делать вот такие вот разборы аргументов в библиотеке :)
Решение в том, чтобы не делать разборов arguments. Метод checkin сделает это за вас. Налицо упрощение при вызове и весьма умеренная сложность при разборе.
Если количество однотипных аргументов зашкаливает, то, согласен, надо передавать объект.
случай, при котором последний аргумент является колбеком (если он конечно является функцией) — распростанённый паттерн, и такое решение будет универсальным:

if(arguments[arguments.length-1] instanceof Function){
    var callback = arguments[arguments.length-1]];
}


в таком случае всегда последний аргумент-функцию можно использовать в качестве колбека, независимо от количества параметров
Согласен, весьма распространённый случай, а как быть с Number и String, которые могут стоять перед колбеком?
.animate( properties [, duration ] [, easing ] [, complete ] )
их в любом случае нужно будет проверять по индексам, тут именно прелесть в том, что колбек можно передать любым параметром
Про колбек ясно, но моё решение состоит как-раз в том, чтобы не перебирать индексы.

if(args.checkin('number a', 'opt object b', 'opt bool c', 'opt function d')){
//Используем параметры args.a, args.b, args.c, args.d

}

foo(1, true, function(){});

И если, как в примере, параметра b нет, то параметр с всё равно будет доступен как args.c
Вы принимаете аргументы и так и сяк, и массивом и в разном порядке. Это все такая медвежья услуга. Потом фиг поймешь как что передавать и что вернет функция. А после смотришь на вызов такой функции, написанный другим человеком, или даже тобой, но довольно давно, и думаешь, а что тут имелось ввиду. Это data, это которая объект data, или которая как строка? А потом еще окажется от наличия или отсутствия какого-то из аргументов функция ведет себя по разному (как гетер и сетер, например). Ну зачем вам нужно через одну точку тянуть весь api, который вы готовы предоставить наружу? Что мешает для вызова пакетом сделать отдельный метод? Что мешает передать null вместо одного из аргументов? Это наглядно, это понятно, это ведет к ожидаемому поведению.

Пожалуйста не надо перенимать худшие практики из jquery. Мне нравится jquery, но вот эта херня с аргументами, которая там творится — худшее что можно было придумать.
Согласен в чём-то. Самое интересное что разрулив ситуацию, которая привела к решению, описанному в статье, я тут-же написал новый метод-обёртку, который устанавливал свежедобавленный аргумент и вызывал исходную функцию.
Возможно получилось бы добиться того-же не усложняя аргументов исходной функции, но больно уж она важнуюю роль играла. Наиболее безопасным показалось поступить с её ядром как с чёрным ящиком.
UFO just landed and posted this here
Не особо понял это к какому участку кода относится?
Вообще иной раз жертвую компактностью ради наглядности.
Необязательные аргументы в середине списка всё-таки не самая удобная вещь. Как по мне, гораздо удобнее передавать опциональные параметры в виде хеша (объекта):

Foo.prototype.useWithBar(barInstance, options) {
  if (options) {
    var baz = options.baz;
    var quux = options.quux;
  }
  /* ... */
}

Достаточно наглядно и не нужно помнить, что четвертый аргумент можно передать третьим, но при этом нужно в качестве второго указать второй, третий, либо null.
(см. также thecodelesscode.com/case/104)

Опять же, в ES Harmony это будет выглядеть намного опрятней:

Foo.prototype.useWithBar(barInstance, {baz, quux}) {
  /* ... */
};
Я оба этих подхода использую. Всегда считал что, например, отличать гетер от сетера по отсутствию аргумента вполне себе логично. Хотя может это и не совсем тот случай.
Можно сказать так: я не пропагандирую свой подход как панацею, но если уж где-то оказывается целесообразным устроить разбор arguments, то лучше это сделать как-то так чем колдовать с индексами.
Очень бы не рекомендовал использовать разные типы передаваемых аргументов в V8 в тех случаях, где требуется высокая нагрузка.
JIT компилятор не сможет использовать нативный код в таких функциях.
Sign up to leave a comment.

Articles