8

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

32

Проблема с обработкой необязательных параметров в JavaScript

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

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

  // Выполнить действия
}

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

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

Есть ли современные альтернативы, например, использование синтаксиса ES6 для задания значений по умолчанию? Буду признателен за любые советы или примеры!

5 ответ(ов)

11

Ваша логика не сработает, если optionalArg будет передан, но будет оцениваться как false. Попробуйте следующее в качестве альтернативы:

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

Или другой вариант записи:

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

Выбирайте тот способ, который лучше всего передает ваше намерение!

0

Если вам нужно передать явное значение 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];
        }
    }

    // ...
}

Этот подход позволяет вам более гибко управлять значениями по умолчанию для аргументов функции.

0

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

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

  ...
}

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

И затем Пол привел один неудачный сценарий! 😄

0

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

/**
 * Обновляет свойства объекта с помощью свойств других объектов. 
 * Все дополнительные ненулевые аргументы будут иметь свои свойства 
 * скопированными в целевой объект в порядке их передачи.
 */
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

Непривязанная проверка типов

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

}
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь