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

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

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

  // Do stuff
}

Есть ли способ лучше?

Существуют ли случаи, когда использование || может потерпеть неудачу?

Это интересно. Передача аргументов в виде ассоциативного массива кажется хорошим способом обработки более чем пары аргументов.

Mark Biek 29.09.2008 18:35

Именно так я и делаю в большинстве случаев. Мои функции с более чем одним аргументом ожидают литерала объекта.

Andrew Hedges 30.09.2008 03:26

@slf Я считаю, что за вашим комментарием следят, поэтому я добавил ответ о arguments в javascript для гуглеров.

Justus Romijn 20.07.2012 18:23

См. Также: stackoverflow.com/questions/894860/…

Malcolm 17.03.2016 20:35
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
833
5
424 617
28
Перейти к ответу Данный вопрос помечен как решенный

Ответы 28

Ответ принят как подходящий

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

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

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

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

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

Я бы использовал тройное равенство ('... lArg === "und ...') на всякий случай.

Jarrod 06.03.2012 02:28

@Jarrod === не требуется при проверке typeof, поскольку typeof возвращает строку, но это не повредит.

Ashwin Prabhu 16.10.2012 11:51

Вероятно, лучше сделать использование === привычкой, чтобы вам не приходилось помнить, при каких обстоятельствах это «безопасно».

jinglesthula 01.11.2012 00:38

Зачем здесь использовать тернарный оператор? Разве второе предложение не просто устанавливает optionalArg = optionalArg ?. Я бы подумал, что достаточно простого IF: if (typeof optionalArg === "undefined") optionalArg = "defaultValue";

Shane N 19.12.2012 22:50

Зачем использовать typeof? optionalArg = (optionalArg === undefined) ? "defaultValue" : optionalArg;

anatoly techtonik 05.02.2013 21:15

Я думаю, что это лучше сигнализирует о намерении - typeof не оценивает операцию, а только проверяет ее тип, что нас и интересует. Кроме того, оценка будет примерно на 40% медленнее (jsperf.com/stackoverflow148901)

Paul Dixon 05.02.2013 21:56

Я нахожу это проблематичным. Используя это, он не исправил ошибку неустановленного параметра, передаваемого в мою функцию. Я записал в консоль значение параметра unset, который я передавал, который проходил через этот защитный слой, и получилось как NaN. Я не понимаю, почему этот ответ так популярен, когда эта ценность может быть понятна. В итоге я использовал isNaN () для решения своей проблемы.

temporary_user_name 21.03.2013 20:43

Ну, вы не говорите о необязательных параметрах - вы действительно являются передаете параметр, поэтому это решение не применимо к вашему случаю. NaN не означает «undefined» - это означает, что вы передали число, но его значение - NaN. Подробнее см. stackoverflow.com/questions/3215120/…

Paul Dixon 22.03.2013 14:36

@PaulDixon просто любопытно, со временем результаты тестов были инвертированы (начиная с Chrome 31) jsperf.com/stackoverflow148901 Похоже, что разработчики Chrome оптимизировали более распространенный используемый метод

Jaime Agudo 29.04.2014 13:48

optionalAgr = optionalAgr === undefined? defaultValue: optionalArg; IMHO typeof избыточен. OptionalArg всегда объявляется в области действия функции.

Víctor Herraiz 29.09.2014 19:16

Моя реализация на переключателе: direction = (typeof direction === 'undefined')? Any_it_was_by_default: (направление === 'внутрь')? истина: ложь;

Robbie Smith 30.03.2015 19:22

@ShaneN Я не думаю, что это имеет значение в js, но тернарность полезна, если вы всегда хотите присвоить что-нибудь переменной. Если нет ветвей if (), распараллелить несколько проще.

Navin 30.04.2015 05:22

почему не просто optionalArg && foo

SuperUberDuper 19.10.2015 18:59

@SuperUberDuper - не работает для значений false

Paul Dixon 19.10.2015 20:57

@PaulDixon, как получилось?

SuperUberDuper 20.10.2015 12:04

А как насчет позиций параметров? function(a, b, callback), где b является необязательным. Если вы опустите b (function(a, callback)), вы можете сравнить значение callback, как если бы это было b. Если нет другого варианта, я бы предложил использовать один параметр json и выполнить проверки внутри: function(myObj), а затем проверьте внутри myObj.b, myObj.callback.

noderman 23.02.2016 20:40

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

Emile Bergeron 07.03.2016 19:12

Вышеупомянутая функция (function(a, b, callback)) очень распространена на Node.js, где callback является необязательным нет, но b может быть. Конечно, вы можете написать базовую функцию таким образом, чтобы определять, является ли второй параметр функцией или нет (если функция, то это обязательный обратный вызов).

noderman 07.03.2016 19:26

optionArg = !! optionArg? optionArg: 'по умолчанию';

Paul Verschoor 03.03.2018 14:14

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

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

  ...

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

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

Я удивлен, что никто не упомянул об использовании массива аргументов!

EvilSyn 29.09.2008 19:16

Что такое «один неудачный сценарий»? Если вы передадите false, null, 0 и т. д., Это не изменит длину массива аргументов. В противном случае использование этого с переключателем (myFunc.arguments.length) хорошо и гибко.

user56reinstatemonica8 20.02.2012 19:14

О, я понимаю - вы имели в виду один неудачный сценарий в OP, а не один неудачный сценарий с вашим решением.

user56reinstatemonica8 20.02.2012 19:14

Если вам нужно вставить буквальный 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];

    // ...
}

почему бы не hasOwnProperty вместо == "undefined"?

Cris Stringfellow 04.03.2013 20:52

Почему не if (!(i in argArray))? И для полноты, перед этим if-заявлением должна быть проверка правильности типа аргумента, например if (typeof argArray !== "object") argArray = [];.

Bart 14.08.2014 17:32

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

/**
 * 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).
  • Дочерние объекты в иерархиях наследования могут настраивать аргументы для своего родительского конструктора по своему усмотрению, применяя собственные значения по умолчанию или обеспечивая использование определенного значения всегда.

ненавижу сложные функции и длинные документы.

EmRa228 05.07.2012 19:58

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

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

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

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

ИЗМЕНИТЬ 17.11.2013 21:33: Я создал пакет для Node.js, который упрощает «перегрузку» функций (методов) под названием параметрический.

+1, но typeof возвращает строку, поэтому вам нужно заключить undefined в кавычки, чтобы это сработало: if (typeof myVariable == "undefined") ...

Richard Inglis 04.06.2012 19:10

Я дал этот ответ, и принятый ответ, борись насмерть. Тернарный метод принимающего ответа был немного медленнее для нескольких тестов, которые я провел: jsperf.com/optional-function-parameters-ternary-vs-manual

Jeromy French 06.02.2015 01:48

@OmShankar Никакой разницы.

BadHorsie 29.10.2015 16:26

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

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


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

  • Он элегантно масштабируется: минимальный дополнительный код для каждого нового значения по умолчанию
  • Вы можете вставить его куда угодно: просто измените количество необходимых аргументов и переменных.
  • Если вы хотите передать 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
  }

}

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


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

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

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

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

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

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

Не уверен, что понимаю это. Разве он не заменил бы значение, когда параметр действительно задан ?! Оо

jeromej 07.06.2014 23:34

Эй, это самый чистый способ, который я видел. Единственная проблема с этим: jsperf.com/optional-parameters-typeof-vs-switch Переключение явно очень медленное ..

JDC 19.06.2014 15:09

Не уверен, что я бы назвал 23,6 миллиона операций в секунду медленными ... это правда, что typeof невероятно быстр, но это не делает switch медленным - просто не таким невероятно быстрым.

user56reinstatemonica8 20.06.2014 01:43

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

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.

+1, потому что я собирался опубликовать свое решение, которое точно такое же: function defaultFor(arg, val) { return typeof arg !== 'undefined' ? arg : val; }

Camilo Martin 02.09.2012 10:02

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

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

Подробнее о них в эта статья о MDN.

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


РЕДАКТИРОВАТЬ (2019-06-12):

Параметры по умолчанию теперь широко поддерживаются современными браузерами. Все версии Internet Исследователь не поддерживают эту функцию. Однако в настоящее время его поддерживают Хром, Fire Fox и Край.

Для меня это достаточно доказательство того, что JavaScript действительно зло. @ThoAppelsin

Zander Rootman 08.09.2014 11:10

JavaScript - зло только для тех, кто его не понимает (я не говорю, что нет, но это мое мнение). Я думаю, что это действительно мощная парадигма (реализации постоянно улучшаются).

trusktr 29.10.2015 22:31

О, привет синтаксис Python. Рад снова тебя видеть.

Hubert Grzeskowiak 21.07.2016 20:36

@HubertGrzeskowiak И синтаксис C# (для значений по умолчанию, если ничего другого).

Zev Spitz 27.02.2017 20:06

@HubertGrzeskowiak то же самое касается многих других языков, не только Python или C# :) Это довольно распространенный подход для значений аргументов по умолчанию.

Ilgıt Yıldırım 23.03.2017 15:48

Поскольку ES6 является текущим стандартом, это правильный ответ.

Outside_Box 21.06.2017 17:22

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

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

Я предлагаю вам использовать 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

}

Больше не поддерживается.

vaughan 02.12.2015 21:28

Я не знаю, почему ответ @Pol не получил голосов, но проверка на соответствие null - хороший выбор. Возможно, более убедительный пример будет иметь больший смысл:

В JavaScript пропущенный параметр подобен объявленной переменной, которая не инициализирована (просто var a1;). А оператор равенства преобразует undefined в null, поэтому он отлично работает как с типами значений, так и с объектами, и именно так 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.info(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.info(optionalArg);
};
bulletproof("required");
bulletproof("required", "provided");
bulletproof("required", null);
bulletproof("required", false);

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

defaultValue
provided
defaultValue
defaultValue

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

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

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

Вот что у меня получилось:

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

  // Do more stuff here ...
}

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

WhoLikesCake({ b : "I do" });

WhoLikesCake({a: false}) бум, ваша функция больше не работает;)

Derek 朕會功夫 01.08.2014 08:41

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

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.

function foo(requiredArg){
  if (arguments.length>1) var optionalArg = arguments[1];
}

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

Shog9 09.04.2014 23:00

Я не думаю, что это требует особых объяснений, это просто ответ на вопрос. Есть много способов выполнения «необязательных параметров функции» в JavaScript. Я видел здесь 3 или 4 других хороших ответа, но я не видел этого ответа, поэтому я его дал. Возможно, это не самый простой и понятный ответ, но он работает.

Dustin Poissant 10.04.2014 23:51

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

user56reinstatemonica8 02.01.2015 02:43

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

Dustin Poissant 08.01.2015 22:24

Близкие -

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

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."; 

Я попробовал несколько вариантов, упомянутых здесь, и проверил их производительность. На данный момент логикор кажется самым быстрым. Хотя со временем это может измениться (разные версии движка 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>

Если вы используете библиотеку Нижнее подчеркивание (вам стоит, это отличная библиотека):

_.defaults(optionalArg, 'defaultValue');

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/

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

Легко написать, но 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') {

}
«Проверка переменной аргументов - ловит все случаи, но писать это наиболее неуклюже» And in loose mode can have negative performance implications thanks to using arguments (not that it usually matters).
T.J. Crowder 19.08.2015 14:00

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

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

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

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

С 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
}

В будущем вы сможете написать это еще короче с распределением объектов (в настоящее время НЕ поддерживается Edge!) - демонстрационная рабочий пример: jsfiddle.net/L7evm21q базовый код: function test(options) { options = { someDefaultParam: '', ...options }; /* do stuff */ } ссылка на будущее: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

jave.web 17.10.2019 23:06

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

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));

Мне это нравится, и я пойду аналогичным путем. (Мой единственный параметр и объект с 20 реквизитами, может быть, 7 очень важны). На самом деле его можно не только редактировать и поддерживать, но и повторно использовать и расширять (например, добавление обратного вызова / испускание чего-либо). Это очень ясно, спасибо вам за это.

Falk 13.07.2018 20:34

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

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.info('value summary of function call:');
            console.info('value1: ' + _value1);
            console.info('value2: ' + _value2);
            console.info('value3: ' + _value3);
            console.info('value4: ' + _value4);
            console.info('');
        }


        //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'
        });
  1. arg || 'default' - отличный способ и работает в 90% случаев

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

    • false
    • 0
    • NaN
    • ""

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

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

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

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

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

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

Опираясь на создание члена объекта 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.info( arg1, arg2, arg3, arg4 ) 
}

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

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

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

argCheck( );
>> undefined false 0 null

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

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

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

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

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

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

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

 for( var x in _default ) {
         x in _arg ? 1 : _arg[x] = _default[x];
        }
    console.info( _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.info( arg, opt );
}

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

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

Bekim Bacaj 08.09.2017 12:31

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

nicholaswmin 02.12.2017 09:40

Основная причина из «множества причин» - в данном случае - это радикальное игнорирование JavaScript. Что касается вашего неявного ложного замечания, что никто не должен объяснять иногда «глупый» отрицательный голос, неверно - потому что, насколько я помню с первого раза, когда я почувствовал, что должен проголосовать против, политика SO требовала / предписывала мне также дать объяснение для этого голоса.

Bekim Bacaj 02.12.2017 19:04

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

nicholaswmin 02.12.2017 19:14

@NicholasKyriakides, где эта конструктивная критика, потому что ее нет. Голос против - это не критика - это наказание без объяснения причин, возможно, просто из-за цвета моей кожи.

Bekim Bacaj 02.12.2017 19:16

it may be simply because of the color of my skin - Я могу почти гарантировать вам, что сообщество совсем не такое. Будьте добрее, когда просите прокомментировать голоса против, и кто-то вам это даст, - это все, что я говорю.

nicholaswmin 02.12.2017 19:19

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

Bekim Bacaj 02.12.2017 19:36

Другие вопросы по теме