Неупорядоченные аргументы функции в Javascript - PullRequest
2 голосов
/ 13 августа 2011

Ниже приведена обычная функция с именованными параметрами:

function who(name, age, isMale, weight)
{
    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}

who('Jack', 30, true, 90); //this is OK.

То, чего я хочу достичь, это;передаете ли вы аргументы по порядку или нет;функция должна выдать аналогичный результат (если не тот же):

who('Jack', 30, true, 90); //should produce the same result with the regular function
who(30, 90, true, 'Jack'); //should produce the same result
who(true, 30, 'Jack', 90); //should produce the same result

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

function who()
{
    var name = getStringInArgs(arguments, 0); //gets first string in arguments
    var isMale = getBooleanInArgs(arguments, 0); //gets first boolean in arguments
    var age = getNumberInArgs(arguments, 0); //gets first number in arguments
    var weight = getNumberInArgs(arguments, 1); //gets second number in arguments

    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}

Здесь есть небольшая проблема;такие функции, как getStringInArgs() и getNumberInArgs(), каждый раз проходят через все аргументы, чтобы найти аргумент по типу в указанной позиции.Я мог бы перебирать аргументы только один раз и сохранять флаги для позиций, но тогда мне пришлось бы делать это внутри функции who ().

Считаете ли вы этот подход логичным и единственным?Есть ли лучший способ сделать это?

РЕДАКТИРОВАТЬ 1: Код выше на самом деле работает.Я просто хочу знать, есть ли лучший способ.

РЕДАКТИРОВАТЬ 2 : Вы можете задаться вопросом, является ли это необходимым или имеет ли это смысл.Основная причина: я пишу функцию jQuery, которая добавляет определенный стиль к элементу DOM.Я хочу, чтобы эта функция обрабатывала свои аргументы как сокращенные значения CSS.

Пример:

border: 1px solid red;
border: solid 1px red; /*will produce the same*/

Итак;вот настоящий и окончательный код до настоящего времени:

(function($){
function getArgument(args, type, occurrence, defaultValue)
{
    if (args.length == 0) return defaultValue;

    var count = 0;
    for(var i = 0; i < args.length; i++)
    {
          if (typeof args[i] === type)
          {
              if (count == occurrence) { return args[i]; }
              else { count++; }
          }
    }
    return defaultValue;
}

$.fn.shadow = function()
{
    var blur = getArgument(arguments, 'number', 0, 3);
    var hLength = getArgument(arguments, 'number', 1, 0);
    var vLength = getArgument(arguments, 'number', 2, 0);
    var color = getArgument(arguments, 'string', 0, '#000');
    var inset = getArgument(arguments, 'boolean', 0, false);
    var strInset = inset ? 'inset ' : '';

    var sValue = strInset + hLength + 'px ' + vLength + 'px ' + blur + 'px ' + color;
    var style = {
        '-moz-box-shadow': sValue,
        '-webkit-box-shadow': sValue,
        'box-shadow': sValue
    };

    return this.each(function()
    {
        $(this).css(style);
    });
}
})(jQuery);

Использование :

$('.dropShadow').shadow(true, 3, 3, 5, '#FF0000');
$('.dropShadow').shadow(3, 3, 5, '#FF0000', true);
$('.dropShadow').shadow();

Ответы [ 8 ]

5 голосов
/ 13 августа 2011

Я считаю, что использование объектов в будущем будет более простым и менее подверженным ошибкам:

var person = {
 name: 'Jack',
 age: 30,
 isMale: true,
 weight: 90
};

who(person);

function who(person){
 alert(person.name + 
  ' (' + (person.isMale ? 'male' : 'female') + '), ' + 
  person.age + ' years old, ' +
  person.weight + ' kg.');
}

Таким образом, когда вы возвращаетесь спустя годы, вам не нужно искать, чтобы узнать, был ли возрастпервое, второе или пятое число и более точно описывает то, что вы пытаетесь достичь.

2 голосов
/ 13 августа 2011

Это кажется излишне сложным, не только с точки зрения функции, которая должна переупорядочивать свои аргументы, но и с точки зрения того, кто вызывает.Вы говорите, что функция может принимать свои параметры в любом порядке , но это не совсем так.Поскольку вы определяете, какая переменная основана на типе, она основывается на том, что каждая переменная имеет свой тип.Имя и пол могут быть где угодно, но числовые аргументы должны быть в определенном порядке.Он также не позволяет кому-либо вводить «30» или «90», которые являются числами, но будут считаться строками - путать его с именем и не определять возраст или вес.

1 голос
/ 13 августа 2011

Вы можете попробовать скопировать массив аргументов во что-то, что вы можете деструктивно обновить:

непроверенный код: Редактировать: я думаю, что это работает сейчас.1008 *

Это все еще O (N ^ 2), так как вы каждый раз просматриваете массив.Однако это не должно быть проблемой, если ваши функции не могут получать сотни аргументов.

1 голос
/ 13 августа 2011

Вы можете кэшировать аргументы определенного типа в массиве arguments. Это большой хак , вы можете следовать тому же шаблону с другими getTypeInArgs

function getNumberInArgs(args, index) {
    if (!args.numbers) {    
      args.numbers = [];
      for (var i=0; i < args.length; i++) {
        // You have to implement isNumber
        if ( isNumber (args[i]) ) {
          args.numbers.push(args[i];
        }      
      }
    }
    return args.numbers[index];
}

Я никогда не слышал о принятии аргументов в любом порядке, кроме функции implode в PHP, и на своей странице документация он помечен как большой взлом по историческим причинам. Так что я бы не стал этого делать. Если порядок слишком запутанный, я бы воспользовался подходом получения буквального объекта, как было предложено WSkid.

0 голосов
/ 07 декабря 2018
function who({name, age, isMale, weight}) 
{
    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.'); 
}

who({name:'Jack', age:30, isMale:true, weight90});

Принимая параметры как объект, позволяет передавать аргументы в любом порядке.

0 голосов
/ 13 августа 2011

Этот код:

function who(items) {    console.log(items.name);    console.log(items.age);    console.log(items.weight);    console.log(items.isMale);}who({name: "Ted", age: 52, weight: 100, isMale: true});

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

КСТАТИ - Решение выше (как и в предыдущем опубликованном) похоже на решение Perl.

0 голосов
/ 13 августа 2011

Я согласен с Гриффином. Это невозможно сделать, если вы не ограничите выбор больше, чем имеете. На самом деле, у вас есть строка, логическое и два числа. Без дополнительных правил о том, что может быть в каком положении, вы не можете сказать, какое число какое. Если вы хотите создать какое-то правило о том, какой номер стоит первым или какой номер идет после какого-либо другого аргумента, вы можете разобраться с ним. В общем, я думаю, что это плохая идея. Гораздо лучше (с точки зрения хорошего программирования) использовать объект, подобный предложенному WSkid.

В любом случае, если вы хотите создать правило, согласно которому вес должен приходить после возраста, тогда это можно сделать так:

function findParm(args, type) {
    for (var i = 0; i < args.length; i++) {
        if (typeof args[i] == type) {
            return(i);
        }
    }
    return(-1);
}

function who(name, age, isMale, weight) {
    // assumes all variables have been passed with the right type
    // age is before weight, but others can be in any order

    var _name, _age, _isMale, _weight, i;

    var args = Array.prototype.slice.call(arguments);
    _name = args[findParm(args, "string")];     // only string parameter
    _isMale = args[findParm(args, "boolean")];  // only boolean parameter
    i = findParm(args, "number");               // first number parameter
    _age = args[i];
    args.splice(i, 1);                          // get rid of first number
    _weight = args[findParm(args, "number")];   // second number parameter

    // you now have the properly ordered parameters in the four local variables
    // _name, _age, _isMale, _weight
}

who("fred", 50, false, 100);

Работа здесь в этой скрипке: http://jsfiddle.net/jfriend00/GP9cW/.

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

function who(items) {
    console.log(items.name);
    console.log(items.age);
    console.log(items.weight);
    console.log(items.isMale);
}

who({name: "Ted", age: 52, weight: 100, isMale: true});
0 голосов
/ 13 августа 2011

Нет способа сделать это, поскольку у вас есть аргументы одного типа.

Если возраст и вес не имеют непересекающихся диапазонов , вы не сможете этого сделать. Как вы должны различать 30 и 60 по весу или возрасту?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...