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

Я всегда обрабатывал необязательные параметры в JavaScript так:

function myFunc(requiredArg, optionalArg){
  optionalArg = optionalArg || 'defaultValue';

  // Do stuff
}

Есть ли лучший способ сделать это?

Есть ли случаи, когда использование || как это потерпит неудачу?

28 ответов

Решение

Ваша логика терпит неудачу, если optionArg передается, но оценивается как ложное - попробуйте это как альтернативу

if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }

Или альтернативная идиома:

optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;

Используйте любую идиому, которая сообщит вам наилучшие намерения!

В ECMAScript 2015 (он же "ES6") вы можете объявить значения аргументов по умолчанию в объявлении функции:

function myFunc(requiredArg, optionalArg = 'defaultValue') {
    // do stuff
}

Подробнее о них в этой статье о MDN (несмотря на название статьи, в JavaScript они называются "аргументы", а не "параметры").

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

Я считаю, что это самый простой, самый читаемый способ:

if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here

Ответ Пола Диксона (по моему скромному мнению) менее читабелен, чем этот, но все сводится к предпочтениям.

Ответ Инсина намного сложнее, но гораздо полезнее для больших функций!

РЕДАКТИРОВАТЬ 17.11.2013 21:33: я создал пакет для Node.js, который облегчает "перегрузку" функций (методов), называемых параметрическими.

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

Другой метод, который выбирают некоторые люди, это использование массива переменных, повторяющихся в списке аргументов. Это выглядит немного аккуратнее, но я думаю, что это немного (очень немного) более интенсивно процесс / память.

function myFunction (argArray) {
    var defaults = {
        'arg1'  :   "value 1",
        'arg2'  :   "value 2",
        'arg3'  :   "value 3",
        'arg4'  :   "value 4"
    }

    for(var i in defaults) 
        if(typeof argArray[i] == "undefined") 
               argArray[i] = defaults[i];

    // ...
}

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

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


Чистое быстрое решение для любого количества аргументов по умолчанию

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

Вот пример для предоставления значений по умолчанию для трех необязательных аргументов (с двумя обязательными аргументами)

function myFunc( requiredA, requiredB,  optionalA, optionalB, optionalC ) {

  switch (arguments.length - 2) { // 2 is the number of required arguments
    case 0:  optionalA = 'Some default';
    case 1:  optionalB = 'Another default';
    case 2:  optionalC = 'Some other default';
    // no breaks between cases: each case implies the next cases are also needed
  }

}

Простая демка. Это похоже на ответ roenving, но легко расширяется для любого количества аргументов по умолчанию, проще в обновлении и использовании arguments не Function.arguments,


Передача и объединение объектов для большей гибкости

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

Хорошим вариантом для этого является передача объектов и слияние с объектом по умолчанию. Это также хорошо для удобства сопровождения (просто позаботьтесь о том, чтобы ваш код читался, чтобы будущие соавторы не оставляли догадываться о возможном содержимом объектов, которые вы передаете).

Пример использования jQuery. Если вы не используете JQuery, вы можете использовать Underscore _.defaults(object, defaults) или просмотрите эти параметры:

function myFunc( args ) {
  var defaults = {
    optionalA: 'Some default',
    optionalB: 'Another default',
    optionalC: 'Some other default'
  };
  args = $.extend({}, defaults, args);
}

Вот простой пример этого в действии.

Вы можете использовать несколько разных схем для этого. Я всегда проверял на аргументы. Длина:

function myFunc(requiredArg, optionalArg){
  optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;

  ...

- делая это, он не может потерпеть неудачу, но я не знаю, есть ли у вашего пути шанс потерпеть неудачу, просто сейчас я не могу придумать сценарий, где он действительно потерпит неудачу...

И тогда Павел предоставил один неудачный сценарий!-)

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

/**
 * Updates an object's properties with other objects' properties. All
 * additional non-falsy arguments will have their properties copied to the
 * destination object, in the order given.
 */
function extend(dest) {
  for (var i = 1, l = arguments.length; i < l; i++) {
    var src = arguments[i]
    if (!src) {
      continue
    }
    for (var property in src) {
      if (src.hasOwnProperty(property)) {
        dest[property] = src[property]
      }
    }
  }
  return dest
}

/**
 * Inherit another function's prototype without invoking the function.
 */
function inherits(child, parent) {
  var F = function() {}
  F.prototype = parent.prototype
  child.prototype = new F()
  child.prototype.constructor = child
  return child
}

... это можно сделать немного лучше.

function Field(kwargs) {
  kwargs = extend({
    required: true, widget: null, label: null, initial: null,
    helpText: null, errorMessages: null
  }, kwargs)
  this.required = kwargs.required
  this.label = kwargs.label
  this.initial = kwargs.initial
  // ...and so on...
}

function CharField(kwargs) {
  kwargs = extend({
    maxLength: null, minLength: null
  }, kwargs)
  this.maxLength = kwargs.maxLength
  this.minLength = kwargs.minLength
  Field.call(this, kwargs)
}
inherits(CharField, Field)

Что хорошего в этом методе?

  • Вы можете опустить столько аргументов, сколько захотите - если вы хотите переопределить значение только одного аргумента, вы можете просто предоставить этот аргумент вместо того, чтобы явно передавать undefined когда, скажем, есть 5 аргументов, и вы хотите настроить только последний аргумент, как вы должны были бы сделать с некоторыми из других предложенных методов.
  • При работе с функцией конструктора для объекта, который наследуется от другого, легко принять любые аргументы, которые требуются конструктору объекта, от которого вы наследуете, так как вам не нужно называть эти аргументы в сигнатуре конструктора, или даже предоставить свои собственные значения по умолчанию (пусть конструктор родительского объекта сделает это за вас, как показано выше, когда CharField звонки Fieldконструктор).
  • Дочерние объекты в иерархиях наследования могут настраивать аргументы для своего родительского конструктора по своему усмотрению, применяя свои собственные значения по умолчанию или гарантируя, что определенное значение всегда будет использоваться.

Свободная проверка типа

Легко написать, но 0, '', false, null а также undefined будет конвертировано в значение по умолчанию, которое может не быть ожидаемым результатом.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
}

Строгая проверка типов

Дольше, но покрывает большинство случаев. Единственный случай, когда он неправильно назначает значение по умолчанию, это когда мы передаем undefined в качестве параметра.

function myFunc(requiredArg, optionalArg) {
    optionalArg = typeof optionalArg !== 'undefined' ? optionalArg : 'defaultValue';
}

Проверка аргументов переменной

Ловит все дела, но писать неуклюже.

function myFunc(requiredArg, optionalArg1, optionalArg2) {
    optionalArg1 = arguments.length > 1 ? optionalArg1 : 'defaultValue';
    optionalArg2 = arguments.length > 2 ? optionalArg2 : 'defaultValue';
}

ES6

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

function myFunc(requiredArg, optionalArg = 'defaultValue') {

}

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

function usageExemple(a,b,c,d){
    //defaults
    a=defaultValue(a,1);
    b=defaultValue(b,2);
    c=defaultValue(c,4);
    d=defaultValue(d,8);

    var x = a+b+c+d;
    return x;
}

Просто объявите эту функцию в глобальной области видимости.

function defaultValue(variable,defaultValue){
    return(typeof variable!=='undefined')?(variable):(defaultValue);
}

Шаблон использования fruit = defaultValue(fruit,'Apple');

*PS вы можете переименовать defaultValue функция с коротким именем, просто не используйте default это зарезервированное слово в JavaScript.

С ES2015/ES6 вы можете воспользоваться Object.assign который может заменить $.extend() или же _.defaults()

function myFunc(requiredArg, options = {}) {
  const defaults = {
    message: 'Hello',
    color: 'red',
    importance: 1
  };

  const settings = Object.assign({}, defaults, options);

  // do stuff
}

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

function myFunc(requiredArg, { message: 'Hello', color: 'red', importance: 1 } = {}) {
  // do stuff
}

Я привык видеть несколько основных вариантов обработки необязательных переменных. Иногда расслабленные версии полезны.

function foo(a, b, c) {
  a = a || "default";   // Matches 0, "", null, undefined, NaN, false.
  a || (a = "default"); // Matches 0, "", null, undefined, NaN, false.

  if (b == null) { b = "default"; } // Matches null, undefined.

  if (typeof c === "undefined") { c = "default"; } // Matches undefined.
}

Ложное значение по умолчанию, используемое с переменной a например, широко используется в Backbone.js.

Если вы используете библиотеку Underscore (вам следует, это потрясающая библиотека):

_.defaults(optionalArg, 'defaultValue');

В ответ на этот вопрос, поиск параметров по умолчанию в EcmaScript 2015, таким образом, просто упомянув...

С ES6 мы можем сделать параметры по умолчанию:

function doSomething(optionalParam = "defaultValue"){
    console.log(optionalParam);//not required to check for falsy values
}

doSomething(); //"defaultValue"
doSomething("myvalue"); //"myvalue"

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

var myCar           = new Car('VW', {gearbox:'automatic', options:['radio', 'airbags 2x']});
var myOtherCar      = new Car('Toyota');

function Car(brand, settings) {
    this.brand      = brand;

    // readable and adjustable code
    settings        = DefaultValue.object(settings, {});
    this.wheels     = DefaultValue.number(settings.wheels, 4);
    this.hasBreaks  = DefaultValue.bool(settings.hasBreaks, true);
    this.gearbox    = DefaultValue.string(settings.gearbox, 'manual');
    this.options    = DefaultValue.array(settings.options, []);

    // instead of doing this the hard way
    settings        = settings || {};
    this.wheels     = (!isNaN(settings.wheels)) ? settings.wheels : 4;
    this.hasBreaks  = (typeof settings.hasBreaks !== 'undefined') ? (settings.hasBreaks === true) : true;
    this.gearbox    = (typeof settings.gearbox === 'string') ? settings.gearbox : 'manual';
    this.options    = (typeof settings.options !== 'undefined' && Array.isArray(settings.options)) ? settings.options : [];
}

Используя этот класс:

(function(ns) {

    var DefaultValue = {

        object: function(input, defaultValue) {
            if (typeof defaultValue !== 'object') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? input : defaultValue;
        },

        bool: function(input, defaultValue) {
            if (typeof defaultValue !== 'boolean') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (input === true) : defaultValue;
        },

        number: function(input, defaultValue) {
            if (isNaN(defaultValue)) throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined' && !isNaN(input)) ? parseFloat(input) : defaultValue;
        },

        // wrap the input in an array if it is not undefined and not an array, for your convenience
        array: function(input, defaultValue) {
            if (typeof defaultValue === 'undefined') throw new Error('invalid defaultValue type');
            return (typeof input !== 'undefined') ? (Array.isArray(input) ? input : [input]) : defaultValue;
        },

        string: function(input, defaultValue) {
            if (typeof defaultValue !== 'string') throw new Error('invalid defaultValue type');
            return (typeof input === 'string') ? input : defaultValue;
        },

    };

    ns.DefaultValue = DefaultValue;

}(this));

Я попробовал некоторые варианты, упомянутые здесь, и тестировал их производительность. В этот момент логика кажется самой быстрой. Хотя со временем это может измениться (разные версии движка JavaScript).

Вот мои результаты (Microsoft Edge 20.10240.16384.0):

Function executed            Operations/sec     Statistics
TypeofFunction('test');          92,169,505     ±1.55%   9% slower
SwitchFuntion('test');            2,904,685     ±2.91%  97% slower
ObjectFunction({param1: 'test'});   924,753     ±1.71%  99% slower
LogicalOrFunction('test');      101,205,173     ±0.92%     fastest
TypeofFunction2('test');         35,636,836     ±0.59%  65% slower

Этот тест производительности можно легко воспроизвести на: http://jsperf.com/optional-parameters-typeof-vs-switch/2

Это код теста:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
    Benchmark.prototype.setup = function() {
        function TypeofFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 = (typeof optParam1 === "undefined") ? "Some default" : optParam1;
            optParam2 = (typeof optParam2 === "undefined") ? "Another default" : optParam2;
            optParam3 = (typeof optParam3 === "undefined") ? "Some other default" : optParam3;
        }

        function TypeofFunction2(param1, optParam1, optParam2, optParam3) {
            optParam1 = defaultValue(optParam1, "Some default");
            optParam2 = defaultValue(optParam2, "Another default");
            optParam3 = defaultValue(optParam3, "Some other default");
        }

        function defaultValue(variable, defaultValue) {
            return (typeof variable !== 'undefined') ? (variable) : (defaultValue);
        }

        function SwitchFuntion(param1, optParam1, optParam2, optParam3) {
            switch (arguments.length - 1) { // <-- 1 is number of required arguments
                case 0:
                    optParam1 = 'Some default';
                case 1:
                    optParam2 = 'Another default';
                case 2:
                    optParam3 = 'Some other default';
            }
        }

        function ObjectFunction(args) {
            var defaults = {
                optParam1: 'Some default',
                optParam2: 'Another default',
                optParam3: 'Some other default'
            }
            args = $.extend({}, defaults, args);
        }

        function LogicalOrFunction(param1, optParam1, optParam2, optParam3) {
            optParam1 || (optParam1 = 'Some default');
            optParam2 || (optParam1 = 'Another default');
            optParam3 || (optParam1 = 'Some other default');
        }
    };
</script>

Я не знаю, почему ответ Пола был отклонен, но проверка против null хороший выбор Может быть, более позитивный пример будет иметь смысл:

В JavaScript пропущенный параметр похож на объявленную переменную, которая не инициализируется (просто var a1;). И оператор равенства преобразует неопределенное в нулевое, так что это прекрасно работает как с типами значений, так и с объектами, и именно так CoffeeScript обрабатывает необязательные параметры.

function overLoad(p1){
    alert(p1 == null); // Caution, don't use the strict comparison: === won't work.
    alert(typeof p1 === 'undefined');
}

overLoad(); // true, true
overLoad(undefined); // true, true. Yes, undefined is treated as null for equality operator.
overLoad(10); // false, false


function overLoad(p1){
    if (p1 == null) p1 = 'default value goes here...';
    //...
}

Хотя есть опасения, что для лучшей семантики typeof variable === 'undefined' немного лучше. Я не собираюсь защищать это, поскольку в основе API лежит вопрос о том, как реализована функция; это не должно интересовать пользователя API.

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

function foo(a, b) {
    // Both a and b will evaluate to undefined when used in an expression
    alert(a); // undefined
    alert(b); // undefined

    alert("0" in arguments); // true
    alert("1" in arguments); // false
}

foo (undefined);

Проверка на undefined не нужна и не так надежна, как могла бы быть, потому что, как указал user568458, предоставленное решение завершается неудачно, если передано значение null или false. Пользователи вашего API могут подумать, что false или null заставит метод избегать этого параметра.

function PaulDixonSolution(required, optionalArg){
   optionalArg = (typeof optionalArg === "undefined") ? "defaultValue" : optionalArg;
   console.log(optionalArg);
};
PaulDixonSolution("required");
PaulDixonSolution("required", "provided");
PaulDixonSolution("required", null);
PaulDixonSolution("required", false);

Результат:

defaultValue
provided
null
false

Последние два потенциально плохие. Вместо этого попробуйте:

function bulletproof(required, optionalArg){
   optionalArg = optionalArg ? optionalArg : "defaultValue";;
   console.log(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);

Что приводит к:

defaultValue
provided
defaultValue
defaultValue

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

  1. arg || 'default' это отличный способ и работает в 90% случаев

  2. Сбой, когда вам нужно передать значения, которые могут быть "ложными"

    • false
    • 0
    • NaN
    • ""

    В этих случаях вам нужно быть более многословным и проверять наличие undefined

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

Во всех случаях, когда optionArg является ложным, вы получите defaultValue.

function myFunc(requiredArg, optionalArg) {
    optionalArg = optionalArg || 'defaultValue';
    console.log(optionalArg);
    // Do stuff
}
myFunc(requiredArg);
myFunc(requiredArg, null);
myFunc(requiredArg, undefined);
myFunc(requiredArg, "");
myFunc(requiredArg, 0);
myFunc(requiredArg, false);

Все вышеперечисленные логи defaultValue, потому что все 6 ложные. В случаях 4, 5, 6 вам может быть не интересно устанавливать опциональное значение Arg как defaultValue, но оно устанавливается, поскольку они ложные.

Вот чем я закончил:

function WhoLikesCake(options) {
  options = options || {};
  var defaultOptions = {
    a : options.a || "Huh?",
    b : options.b || "I don't like cake."
  }
  console.log('a: ' + defaultOptions.b + ' - b: ' + defaultOptions.b);

  // Do more stuff here ...
}

Вызывается так:

WhoLikesCake({ b : "I do" });
function Default(variable, new_value)
{
    if(new_value === undefined) { return (variable === undefined) ? null : variable; }
    return (variable === undefined) ? new_value : variable;
}

var a = 2, b = "hello", c = true, d;

var test = Default(a, 0),
test2 = Default(b, "Hi"),
test3 = Default(c, false),
test4 = Default(d, "Hello world");

window.alert(test + "\n" + test2 + "\n" + test3 + "\n" + test4);

http://jsfiddle.net/mq60hqrf/

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

function YourFunction(optionalArguments) {
            //var scope = this;

            //set the defaults
            var _value1 = 'defaultValue1';
            var _value2 = 'defaultValue2';
            var _value3 = null;
            var _value4 = false;

            //check the optional arguments if they are set to override defaults...
            if (typeof optionalArguments !== 'undefined') {

                if (typeof optionalArguments.param1 !== 'undefined')
                    _value1 = optionalArguments.param1;

                if (typeof optionalArguments.param2 !== 'undefined')
                    _value2 = optionalArguments.param2;

                if (typeof optionalArguments.param3 !== 'undefined')
                    _value3 = optionalArguments.param3;

                if (typeof optionalArguments.param4 !== 'undefined')
                    //use custom parameter validation if needed, in this case for javascript boolean
                   _value4 = (optionalArguments.param4 === true || optionalArguments.param4 === 'true');
            }

            console.log('value summary of function call:');
            console.log('value1: ' + _value1);
            console.log('value2: ' + _value2);
            console.log('value3: ' + _value3);
            console.log('value4: ' + _value4);
            console.log('');
        }


        //call your function in any way you want. You can leave parameters. Order is not important. Here some examples:
        YourFunction({
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
            param3: 'yourGivenValue3',
            param4: true,
        });

        //order is not important
        YourFunction({
            param4: false,
            param1: 'yourGivenValue1',
            param2: 'yourGivenValue2',
        });

        //uses all default values
        YourFunction();

        //keeps value4 false, because not a valid value is given
        YourFunction({
            param4: 'not a valid bool'
        });

Народ -

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

function person(firstname, lastname, age, eyecolor)
{
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.eyecolor = eyecolor;
// if(null==eyecolor)
//   this.eyecolor = "unknown1";
//if(typeof(eyecolor)==='undefined') 
//   this.eyecolor = "unknown2";
// if(!eyecolor)
//   this.eyecolor = "unknown3";
this.eyecolor = this.eyecolor || "unknown4";
}

var myFather = new person("John", "Doe", 60);
var myMother = new person("Sally", "Rally", 48, "green");

var elem = document.getElementById("demo");
elem.innerHTML = "My father " +
              myFather.firstname + " " +
              myFather.lastname + " is " +
              myFather.age + " with " +
              myFather.eyecolor + " eyes.<br/>" +
              "My mother " +
              myMother.firstname + " " +
              myMother.lastname + " is " +
              myMother.age + " with " +
              myMother.eyecolor + " eyes."; 

Поправьте меня, если я ошибаюсь, но это кажется самым простым способом (во всяком случае, для одного аргумента):

function myFunction(Required,Optional)
{
    if (arguments.length<2) Optional = "Default";
    //Your code
}

Они короче версии оператора typeof.

function foo(a, b) {
    a !== undefined || (a = 'defaultA');
    if(b === undefined) b = 'defaultB';
    ...
}

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

Полагаясь на создание члена объекта arguments, который даже не создается, если аргумент отсутствует, независимо от того, может ли он быть объявлен, мы можем написать вашу функцию следующим образом:

  function myFunc(requiredArg, optionalArg){
        optionalArg = 1 in arguments ? optionalArg : 'defaultValue';
  //do stuff
  }

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

В следующем демонстрационном коде мы намеренно поместим типизированное и бесценное неопределенное значение в качестве значения по умолчанию, чтобы можно было определить, может ли оно произойти сбой при ложных значениях аргумента, таких как 0 false и т. Д., Или же оно будет вести себя как ожидалось.

function argCheck( arg1, arg2, arg3 ){

       arg1 = 0 in arguments || undefined;
       arg2 = 1 in arguments || false;
       arg3 = 2 in arguments || 0;
   var arg4 = 3 in arguments || null;

   console.log( arg1, arg2, arg3, arg4 ) 
}

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

argCheck( "", 0, false, null );
>> true true true true

Это означает, что они не потерпели неудачу в признании / как ожидаемые значения аргумента. Здесь у нас есть проверка со всеми отсутствующими аргументами, которая согласно нашему алгоритму должна получать значения по умолчанию, даже если они ложные.

argCheck( );
>> undefined false 0 null

Как мы видим, аргументы arg1, arg2, arg3 и необъявленный arg4 возвращают свои точные значения по умолчанию, как указано. Поскольку теперь мы убедились, что это работает, мы можем переписать функцию, которая на самом деле сможет использовать их, как в первом примере, используя: либо if, либо троичное условие.

В функциях, которые имеют более одного необязательного аргумента - проходной цикл, могли бы сэкономить нам несколько битов. Но поскольку имена аргументов не инициализируются, если их значения не предоставлены, мы не можем получить к ним доступ по именам, даже если мы программно записали значение по умолчанию, мы можем получить к ним доступ только по аргументам [index], что бесполезно для читабельности кода.

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

argCheck("a",,22,{});

потому что это бросит! Что делает невозможным замену нашего аргумента конкретным ложным типом желаемого значения по умолчанию. Что глупо, поскольку объект arguments является массивоподобным объектом и, как ожидается, будет поддерживать этот синтаксис и соглашение как есть, изначально или по умолчанию!

Из-за этого близорукого решения мы больше не можем надеяться написать такую ​​функцию:

function argCheck( ) {
    var _default = [undefined, 0, false, null ],
        _arg = arguments;

 for( var x in _default ) {
         x in _arg ? 1 : _arg[x] = _default[x];
        }
    console.log( _arg[0],_arg[1],_arg[2],_arg[3] );
}

в этом случае мы сможем записать каждое значение по умолчанию желаемого типа в строку аргументов и по крайней мере получить к ним доступ через args.index.

Например, этот вызов функции даст:

argCheck();
>>undefined 0 false null

как определено в нашем массиве значений аргументов по умолчанию. Однако все еще возможно следующее:

argCheck({})
>>Object {  } 0 false null

argCheck({}, [])
>>Object {  } Array [  ] false null

Но, к сожалению, нет

 argCheck("a",,,22);
 >>SyntaxError: expected expression, got ','

Что в противном случае будет входить:

>>a 0 false 22

но это в лучшем мире! Однако - для первоначального вопроса - самая верхняя функция подойдет. например:

function argCheck( arg, opt ) {
         1 in arguments ? 1 : opt = "default";
         console.log( arg, opt );
}

ps: извините за то, что не сохранил типы выбранных значений по умолчанию в моих аргументах ввода при их записи.

Я предлагаю вам использовать ArgueJS следующим образом:

function myFunc(){
  arguments = __({requiredArg: undefined, optionalArg: [undefined: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}

Вы также можете заменить undefined по типу аргумента, который вы ожидаете получить, вот так:

function myFunc(){
  arguments = __({requiredArg: Number, optionalArg: [String: 'defaultValue'})

  //do stuff, using arguments.requiredArg and arguments.optionalArg
  //    to access your arguments

}
function foo(requiredArg){
  if(arguments.length>1) var optionalArg = arguments[1];
}
Другие вопросы по тегам