Как лучше реализовать необязательные параметры функций в JavaScript?
Проблема с обработкой необязательных параметров в JavaScript
Я всегда обрабатывал необязательные параметры в JavaScript следующим образом:
function myFunc(requiredArg, optionalArg) {
optionalArg = optionalArg || 'defaultValue';
// Выполнить действия
}
Однако задумываюсь, есть ли более современный или лучший способ сделать это?
Кроме того, существуют ли случаи, когда использование оператора ||
в этом контексте может привести к ошибкам или неожиданному поведению?
Есть ли современные альтернативы, например, использование синтаксиса ES6 для задания значений по умолчанию? Буду признателен за любые советы или примеры!
5 ответ(ов)
Ваша логика не сработает, если optionalArg
будет передан, но будет оцениваться как false
. Попробуйте следующее в качестве альтернативы:
if (typeof optionalArg === 'undefined') { optionalArg = 'default'; }
Или другой вариант записи:
optionalArg = (typeof optionalArg === 'undefined') ? 'default' : optionalArg;
Выбирайте тот способ, который лучше всего передает ваше намерение!
Если вам нужно передать явное значение 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];
}
}
// ...
}
Этот подход позволяет вам более гибко управлять значениями по умолчанию для аргументов функции.
Вы можете использовать разные схемы для этого. Я всегда проверяю количество аргументов с помощью arguments.length
:
function myFunc(requiredArg, optionalArg){
optionalArg = arguments.length < 2 ? 'defaultValue' : optionalArg;
...
}
Используя этот способ, функция не может потерпеть неудачу. Но я не знаю, есть ли у вашего варианта шанс на ошибку. Сейчас не могу придумать сценарий, в котором он мог бы не сработать...
И затем Пол привел один неудачный сценарий! 😄
Согласно ответу Оли, я использую объект аргументов и объект, который задает значения по умолчанию. С небольшими улучшениями...
/**
* Обновляет свойства объекта с помощью свойств других объектов.
* Все дополнительные ненулевые аргументы будут иметь свои свойства
* скопированными в целевой объект в порядке их передачи.
*/
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
}
/**
* Наследует прототип другой функции без вызова этой функции.
*/
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
// ...и так далее...
}
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') {
}
Установка значения по умолчанию для параметра функции в JavaScript
JavaScript: Переменное количество аргументов для функции
В чем разница между call и apply?
Определение глобальной переменной в функции JavaScript
Декораторы с параметрами?