Я всегда обрабатывал необязательные параметры в JavaScript следующим образом:
function myFunc(requiredArg, optionalArg){
optionalArg = optionalArg || 'defaultValue';
// Do stuff
}
Есть ли способ лучше?
Существуют ли случаи, когда использование || может потерпеть неудачу?
Это интересно. Передача аргументов в виде ассоциативного массива кажется хорошим способом обработки более чем пары аргументов.
Именно так я и делаю в большинстве случаев. Мои функции с более чем одним аргументом ожидают литерала объекта.
@slf Я считаю, что за вашим комментарием следят, поэтому я добавил ответ о arguments в javascript для гуглеров.
См. Также: stackoverflow.com/questions/894860/…



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Ваша логика не работает, если optionalArg передается, но оценивается как false - попробуйте это как альтернативу
if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }
Или альтернативная идиома:
optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;
Используйте ту идиому, которая лучше всего передает ваше намерение!
Я бы использовал тройное равенство ('... lArg === "und ...') на всякий случай.
@Jarrod === не требуется при проверке typeof, поскольку typeof возвращает строку, но это не повредит.
Вероятно, лучше сделать использование === привычкой, чтобы вам не приходилось помнить, при каких обстоятельствах это «безопасно».
Зачем здесь использовать тернарный оператор? Разве второе предложение не просто устанавливает optionalArg = optionalArg ?. Я бы подумал, что достаточно простого IF: if (typeof optionalArg === "undefined") optionalArg = "defaultValue";
Зачем использовать typeof? optionalArg = (optionalArg === undefined) ? "defaultValue" : optionalArg;
Я думаю, что это лучше сигнализирует о намерении - typeof не оценивает операцию, а только проверяет ее тип, что нас и интересует. Кроме того, оценка будет примерно на 40% медленнее (jsperf.com/stackoverflow148901)
Я нахожу это проблематичным. Используя это, он не исправил ошибку неустановленного параметра, передаваемого в мою функцию. Я записал в консоль значение параметра unset, который я передавал, который проходил через этот защитный слой, и получилось как NaN. Я не понимаю, почему этот ответ так популярен, когда эта ценность может быть понятна. В итоге я использовал isNaN () для решения своей проблемы.
Ну, вы не говорите о необязательных параметрах - вы действительно являются передаете параметр, поэтому это решение не применимо к вашему случаю. NaN не означает «undefined» - это означает, что вы передали число, но его значение - NaN. Подробнее см. stackoverflow.com/questions/3215120/…
@PaulDixon просто любопытно, со временем результаты тестов были инвертированы (начиная с Chrome 31) jsperf.com/stackoverflow148901 Похоже, что разработчики Chrome оптимизировали более распространенный используемый метод
optionalAgr = optionalAgr === undefined? defaultValue: optionalArg; IMHO typeof избыточен. OptionalArg всегда объявляется в области действия функции.
Моя реализация на переключателе: direction = (typeof direction === 'undefined')? Any_it_was_by_default: (направление === 'внутрь')? истина: ложь;
@ShaneN Я не думаю, что это имеет значение в js, но тернарность полезна, если вы всегда хотите присвоить что-нибудь переменной. Если нет ветвей if (), распараллелить несколько проще.
почему не просто optionalArg && foo
@SuperUberDuper - не работает для значений false
@PaulDixon, как получилось?
А как насчет позиций параметров? function(a, b, callback), где b является необязательным. Если вы опустите b (function(a, callback)), вы можете сравнить значение callback, как если бы это было b. Если нет другого варианта, я бы предложил использовать один параметр json и выполнить проверки внутри: function(myObj), а затем проверьте внутри myObj.b, myObj.callback.
@noderman - это стандарт на многих языках, официально поддерживающий необязательные параметры, чтобы они появлялись последними. Если существует более одного необязательного параметра, вы не можете пропустить первый и указать второй. Если вы хотите предоставить второй, вы должны предоставить оба.
Вышеупомянутая функция (function(a, b, callback)) очень распространена на Node.js, где callback является необязательным нет, но b может быть. Конечно, вы можете написать базовую функцию таким образом, чтобы определять, является ли второй параметр функцией или нет (если функция, то это обязательный обратный вызов).
optionArg = !! optionArg? optionArg: 'по умолчанию';
Для этого можно использовать несколько разных схем. Я всегда проверял arguments.length:
function myFunc(requiredArg, optionalArg){
optionalArg = myFunc.arguments.length<2 ? 'defaultValue' : optionalArg;
...
- при этом он не может потерпеть неудачу, но я не знаю, есть ли у вашего пути шанс на провал, просто сейчас я не могу придумать сценарий, где он действительно потерпит неудачу ...
А потом Пол представил один неудачный сценарий! -)
Я удивлен, что никто не упомянул об использовании массива аргументов!
Что такое «один неудачный сценарий»? Если вы передадите false, null, 0 и т. д., Это не изменит длину массива аргументов. В противном случае использование этого с переключателем (myFunc.arguments.length) хорошо и гибко.
О, я понимаю - вы имели в виду один неудачный сценарий в OP, а не один неудачный сценарий с вашим решением.
Если вам нужно вставить буквальный 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"?
Почему не if (!(i in argArray))? И для полноты, перед этим if-заявлением должна быть проверка правильности типа аргумента, например if (typeof argArray !== "object") argArray = [];.
Как и в ответе Оли, я использую объект аргумента и объект, который определяет значения по умолчанию. С небольшим количеством сахара ...
/**
* 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).ненавижу сложные функции и длинные документы.
Я считаю, что это самый простой и читаемый способ:
if (typeof myVariable === 'undefined') { myVariable = 'default'; }
//use myVariable here
Ответ Пола Диксона (по моему скромному мнению) менее читабелен, чем этот, но все сводится к предпочтениям.
Ответ insin намного более продвинутый, но гораздо более полезный для больших функций!
ИЗМЕНИТЬ 17.11.2013 21:33: Я создал пакет для Node.js, который упрощает «перегрузку» функций (методов) под названием параметрический.
+1, но typeof возвращает строку, поэтому вам нужно заключить undefined в кавычки, чтобы это сработало: if (typeof myVariable == "undefined") ...
Я дал этот ответ, и принятый ответ, борись насмерть. Тернарный метод принимающего ответа был немного медленнее для нескольких тестов, которые я провел: jsperf.com/optional-function-parameters-ternary-vs-manual
@OmShankar Никакой разницы.
В идеале вы должны провести рефакторинг, чтобы передать объект и слияние его с помощью объекта по умолчанию, поэтому порядок, в котором передаются аргументы, не имеет значения (см. Второй раздел этого ответа ниже).
Однако, если вам нужно что-то быстрое, надежное, простое в использовании и не громоздкое, попробуйте следующее:
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);
}
Вот простой пример этого в действии.
Не уверен, что понимаю это. Разве он не заменил бы значение, когда параметр действительно задан ?! Оо
Эй, это самый чистый способ, который я видел. Единственная проблема с этим: jsperf.com/optional-parameters-typeof-vs-switch Переключение явно очень медленное ..
Не уверен, что я бы назвал 23,6 миллиона операций в секунду медленными ... это правда, что typeof невероятно быстр, но это не делает switch медленным - просто не таким невероятно быстрым.
Если вы часто используете значения по умолчанию, это кажется более читаемым:
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; }
В ECMAScript 2015 (он же «ES6») вы можете объявить значения аргументов по умолчанию в объявлении функции:
function myFunc(requiredArg, optionalArg = 'defaultValue') {
// do stuff
}
Подробнее о них в эта статья о MDN.
В настоящее время это поддерживается только Firefox, но, поскольку стандарт был завершен, ожидается, что поддержка быстро улучшится.
РЕДАКТИРОВАТЬ (2019-06-12):
Параметры по умолчанию теперь широко поддерживаются современными браузерами. Все версии Internet Исследователь не поддерживают эту функцию. Однако в настоящее время его поддерживают Хром, Fire Fox и Край.
Для меня это достаточно доказательство того, что JavaScript действительно зло. @ThoAppelsin
JavaScript - зло только для тех, кто его не понимает (я не говорю, что нет, но это мое мнение). Я думаю, что это действительно мощная парадигма (реализации постоянно улучшаются).
О, привет синтаксис Python. Рад снова тебя видеть.
@HubertGrzeskowiak И синтаксис C# (для значений по умолчанию, если ничего другого).
@HubertGrzeskowiak то же самое касается многих других языков, не только Python или C# :) Это довольно распространенный подход для значений аргументов по умолчанию.
Поскольку ES6 является текущим стандартом, это правильный ответ.
Поправьте меня, если я ошибаюсь, но это кажется самым простым способом (во всяком случае, для одного аргумента):
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
}
Больше не поддерживается.
Я не знаю, почему ответ @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}) бум, ваша функция больше не работает;)
Я привык видеть несколько основных вариантов обработки необязательных переменных. Иногда могут быть полезны расслабленные версии.
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];
}
Возможно, вы захотите исправить эту опечатку и добавить объяснение того, что вы здесь рекомендуете.
Я не думаю, что это требует особых объяснений, это просто ответ на вопрос. Есть много способов выполнения «необязательных параметров функции» в JavaScript. Я видел здесь 3 или 4 других хороших ответа, но я не видел этого ответа, поэтому я его дал. Возможно, это не самый простой и понятный ответ, но он работает.
Это то же самое, что и ответ Ренвинга, но не дает значения по умолчанию. Тем не менее, мне очень нравится удобочитаемость определения необязательных аргументов отдельно от обязательных: если это цель вашего ответа, было бы полезно сказать об этом
Я не думаю, что мой ответ в любом случае лучший. Я предпочитаю ответ angelcool.net. Я просто указывал, что это еще один вариант. Я бы никогда не использовал этот метод, я просто подумал, что спрашивающий предпочел бы, чтобы были предложены все доступные варианты, и они могут сами выбрать, какой метод им больше нравится, и я заметил, что этот ответ не был дан, и поэтому, чтобы попытаться предоставить спрашивающий с наиболее полным ответом Я считаю, что этот вариант (хотя и отстой) должен быть предоставлен.
Близкие -
Посмотрев на эти и другие решения, я опробовал некоторые из них, используя в качестве основы фрагмент кода, изначально взятый из 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);
Свободная проверка типа
Легко написать, но 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') {
}
arguments (not that it usually matters).
Приземлился к этому вопросу, ища параметры по умолчанию в 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/…
Во время проекта я заметил, что слишком часто повторяюсь с необязательными параметрами и настройками, поэтому я создал класс, который обрабатывает проверку типов и присваивает значение по умолчанию, что приводит к аккуратному и удобочитаемому коду. Посмотрите пример и дайте мне знать, работает ли это для вас.
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 очень важны). На самом деле его можно не только редактировать и поддерживать, но и повторно использовать и расширять (например, добавление обратного вызова / испускание чего-либо). Это очень ясно, спасибо вам за это.
Вот мое решение. При этом вы можете оставить любой параметр, который хотите. Порядок необязательных параметров не важен, и вы можете добавить настраиваемую проверку.
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'
});
arg || 'default' - отличный способ и работает в 90% случаев
Не работает, когда вам нужно передать значения, которые могут быть "ложными"
false0NaN""В этих случаях вам нужно быть более подробным и проверить наличие undefined.
Также будьте осторожны, когда сначала у вас есть необязательные аргументы, вы должны знать типы всех ваших аргументов.
Во всех случаях, когда 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 только что проголосовал за лучший и наиболее полный ответ на этот вопрос, даже не зная почему. Может потому, что его продумали и потерялись в процессе. Удачи в следующий раз с твоими способностями к чтению и пониманию. :)
Есть много причин для того, чтобы проголосовать против, и никто не должен вам объяснять, почему они это сделали. Не принимайте это слишком личное, это неконструктивно и плохо выглядит
Основная причина из «множества причин» - в данном случае - это радикальное игнорирование JavaScript. Что касается вашего неявного ложного замечания, что никто не должен объяснять иногда «глупый» отрицательный голос, неверно - потому что, насколько я помню с первого раза, когда я почувствовал, что должен проголосовать против, политика SO требовала / предписывала мне также дать объяснение для этого голоса.
Неправильное использование громких слов не отменяет того факта, что более чем в одном из ваших ответов вы получите тот же ответ, что и я. Возможно, в следующий раз вам будет лучше принять это как конструктивную критику. Если все выглядят невежественными, кроме вас, возможно, это вы, возможно, невежественны.
@NicholasKyriakides, где эта конструктивная критика, потому что ее нет. Голос против - это не критика - это наказание без объяснения причин, возможно, просто из-за цвета моей кожи.
it may be simply because of the color of my skin - Я могу почти гарантировать вам, что сообщество совсем не такое. Будьте добрее, когда просите прокомментировать голоса против, и кто-то вам это даст, - это все, что я говорю.
Сообщество не такое, но оно состоит из людей, которые никогда не знали друг друга. -Я был очень милым, и все же - всем известно, что греки ненавидят албанцев. :) Вы должны указать на мою ошибку для честного и конструктивного отрицательного голоса, от которого выиграют все. В противном случае отрицание качественного ответа является злонамеренным действием и противоречит интересам сообщества.