Как лучше всего определить, не отправляется ли аргумент функции JavaScript

Я видел 2 метода определения того, был ли аргумент передан функции JavaScript. Мне интересно, лучше ли один метод другого или просто плохо использовать?

 function Test(argument1, argument2) {
      if (Test.arguments.length == 1) argument2 = 'blah';

      alert(argument2);
 }

 Test('test');

Или же

 function Test(argument1, argument2) {
      argument2 = argument2 || 'blah';

      alert(argument2);
 }

 Test('test');

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

Другой вариант, упомянутый Том:

function Test(argument1, argument2) {
    if (argument2 === null) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Согласно комментарию Хуана, было бы лучше изменить предложение Тома на:

function Test(argument1, argument2) {
    if (argument2 === undefined) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Не переданный аргумент считается неопределенным. Тестирование со строгим равенством с нулевым значением завершится неудачно. Вы должны использовать строгое равенство с undefined.

Juan Mendes 17.01.2011 23:17

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

Luca Matteis 04.01.2009 20:43

Помните: argument2 || 'blah'; выдаст «бла», если argument2 - это false (!), А не просто, если он не определен. Если argument2 является логическим, и функция передается для него false, эта строка вернет 'blah', несмотря на то, что argument2 правильно определен..

Sandy Gifford 26.04.2013 21:39

@SandyGifford: Та же проблема, если argument2 - это 0, '' или null.

rvighne 16.06.2014 21:21

@rvighne Совершенно верно. Уникальная интерпретация объектов и приведения в Javascript - это одновременно и лучшее, и худшее.

Sandy Gifford 16.06.2014 22:34
Поведение ключевого слова "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) для оценки ваших знаний,...
242
5
165 324
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

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

Есть несколько разных способов проверить, был ли передан аргумент функции. В дополнение к двум, которые вы упомянули в своем (исходном) вопросе - проверка arguments.length или использование оператора || для предоставления значений по умолчанию - можно также явно проверить аргументы для undefined через argument2 === undefined или typeof argument2 === 'undefined', если один из них параноик (см. Комментарии).

Использование оператора || стало стандартной практикой - это делают все крутые ребята, но будьте осторожны: значение по умолчанию будет активировано, если аргумент оценивается как false, что означает, что на самом деле это может быть undefined, null, false, 0, '' (или все остальное, для чего Boolean(...) возвращает false).

Итак, вопрос в том, когда использовать какую проверку, поскольку все они дают несколько разные результаты.

Проверка arguments.length демонстрирует «наиболее правильное» поведение, но может оказаться невозможным, если имеется более одного необязательного аргумента.

Следующий «лучший» тест на undefined - он «терпит неудачу» только в том случае, если функция явно вызывается со значением undefined, что, по всей вероятности, должно рассматриваться так же, как и пропуск аргумента.

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

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

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

Другой хороший способ предоставить значения по умолчанию с помощью arguments.length - это пропустить метки оператора switch:

function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
    switch(arguments.length) {
        case 1: optionalArg1 = 'default1';
        case 2: optionalArg2 = 'default2';
        case 3: optionalArg3 = 'default3';
        case 4: break;
        default: throw new Error('illegal argument count')
    }
    // do stuff
}

Обратной стороной этого является то, что намерения программиста не очевидны (визуально) и используют «магические числа»; поэтому это, возможно, подвержено ошибкам.

Фактически вы должны проверить typeof argument2 === "undefined", если кто-то определяет "undefined".

JW. 04.01.2009 21:19

Я добавлю уведомление - но какие больные ублюдки делают такие вещи?

Christoph 04.01.2009 21:24

Я никого не знаю, поэтому обычно использую === undefined. Но кто-то указал мне (в аналогичной теме), что undefined на самом деле не является ключевым словом JavaScript, так что это своего рода взлом.

JW. 04.01.2009 22:38

undefined - это переменная в глобальном пространстве. Поиск этой переменной в глобальной области выполняется медленнее, чем для переменной в локальной области. Но самый быстрый - использовать typeof x === "undefined"

some 04.01.2009 23:40

Интересно. С другой стороны, сравнение === undefined может быть быстрее, чем сравнение строк. Мои тесты, похоже, показывают, что вы правы: x === undefined требуется ~ 1,5 раза больше времени typeof x === 'undefined'

Christoph 05.01.2009 00:26

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

Juan Mendes 17.01.2011 23:19

@Juan: неизменяемые строки не подразумевают уникальных строк, и только последнее будет означать эквивалентность равенства строк и равенства указателей; возьмите виртуальную машину Java в качестве примера языковой среды выполнения с неизменяемыми, но - в общем случае - неуникальными строками

Christoph 18.01.2011 01:01

@ Кристоф, это очень интересно. Я всегда предполагал, что неизменные строки будут сочетаться с уникальными строками. Зачем создавать два объекта с одинаковым содержимым, если их нельзя изменить?

Juan Mendes 18.01.2011 01:25

@Juan: уникальные строки штрафуют за создание строки - если содержимое строки неизвестно во время компиляции, вам нужно будет использовать строковый кеш (какую-то хеш-таблицу или дерево поиска) во время выполнения, чтобы гарантировать, что вы не создаете дубликат; afaik, даже если они не используют уникальные строки, многие фреймворки для обработки строк предпочитают неизменность альтернативам, таким как копирование при записи по разным причинам (более простые алгоритмы, более легкое управление памятью, ...)

Christoph 18.01.2011 03:12

@Cristoph: прочитав ваш комментарий, я поспрашивал. Я смог доказать, что сравнение строк, безусловно, осуществляется не (только) сравнением указателей, поскольку сравнение гигантской строки занимает больше времени, чем небольшая строка. Однако сравнение двух гигантских строк действительно медленно, только если они были построены с помощью конкатенации, но очень быстро, если вторая была создана как присваивание первой. Так что это, вероятно, работает с помощью теста указателя, за которым следует тестирование по буквам. Итак, да, я был полон дерьма :) Спасибо, что просветили меня ...

Juan Mendes 18.01.2011 04:08

ребята, а что, если последний параметр функции - это callback ()?

Cmag 06.12.2014 23:57

вместо ключевого слова «undefined» вы можете написать «void 0». Это спасает пару персонажей. Компилятор Google Closure использует этот трюк. То есть: (undefined === argument2) можно переписать в (void 0 === argument2)

rosell.dk 18.08.2016 10:20

Если вы собираетесь использовать эту функцию дважды, решение с наименьшим количеством символов - это передать ее помощнику: function u (a) {return void 0 === a}.

rosell.dk 18.08.2016 10:23

Извините, я все еще не могу комментировать, поэтому, чтобы ответить на ответ Тома ... В javascript (undefined! = Null) == false Фактически, эта функция не будет работать с "null", вы должны использовать "undefined"

И Том получил два голоса за неправильный ответ - всегда приятно знать, насколько хорошо работают эти системы сообщества;)

Christoph 04.01.2009 20:53

Это один из немногих случаев, когда я нахожу тест:

if (! argument2) {  

}

работает довольно хорошо и синтаксически имеет правильное значение.

(С одновременным ограничением, что я не допущу допустимого нулевого значения для argument2, которое имеет другое значение; но это сбивает с толку В самом деле.)

Обновлено:

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

Мое личное предпочтение (без критики по поводу других предпочтений) - минимализм. Чем меньше в коде должно быть сказано, пока я последователен и лаконичен, тем меньше кто-то должен понять, чтобы правильно вывести мое значение.

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

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

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

Я убедился в этом, сравнивая исчерпывающий код ActionScript 3 с элегантным кодом javascript. AS3 может в 3 или 4 раза превышать объем js, и я подозреваю, что надежность, по крайней мере, не лучше, просто из-за количества (в 3-4 раза) принятых решений по кодированию.

Как вы говорите, Shog9, YMMV. : D

if (! аргумент2) аргумент2 = 'по умолчанию' эквивалентен аргументу2 = аргумент2 || 'default' - вторая версия мне кажется визуально более приятной ...

Christoph 04.01.2009 21:01

И я нахожу это более многословным и отвлекающим; но я уверен, что это личные предпочтения.

dkretz 04.01.2009 21:02

@le dorfier: он также исключает использование пустых строк, 0 и логического значения false.

Shog9 04.01.2009 21:03

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

Shog9 04.01.2009 21:04

что, если параметр 2 является логическим === false; или функция {return false;}?

fresko 12.10.2016 13:15

Даже если вы передадите обратный вызов @fresko, этот обратный вызов будет равен true, поскольку это функция. Функция не вызывается, поэтому она не возвращает ложное значение.

Bronzdragon 13.12.2018 19:18

Это, безусловно, лучший ответ! И с точкой! (Мне действительно интересно, почему вся эта возня (включая длинный комментарий, который ее сопровождает! :))

Apostolos 02.03.2021 10:43

Есть существенные отличия. Давайте настроим несколько тестовых примеров:

var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");

При использовании первого метода, который вы описываете, только второй тест будет использовать значение по умолчанию. Второй метод будет использовать по умолчанию все, кроме первого (поскольку JS преобразует undefined, null, 0 и "" в логическое значение false. И если вы использовали метод Тома, только четвертый тест будет использовать значение по умолчанию!

Какой метод вы выберете, действительно зависит от вашего предполагаемого поведения. Если для undefined допустимы значения, отличные от argument2, то вам, вероятно, понадобится какое-то изменение первого; если требуется ненулевое, ненулевое, непустое значение, тогда идеально подходит второй метод - действительно, он часто используется для быстрого исключения такого широкого диапазона значений из рассмотрения.

url = url === undefined ? location.href : url;

Ответ голый. Некоторое объяснение не повредит.

Paul Rooney 13.02.2017 03:50

Это тернарный оператор, который кратко говорит: если url не определен (отсутствует), установите переменную url как location.href (текущая веб-страница), в противном случае установите переменную url как определенный url.

rmooney 04.09.2019 03:16

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

function foo(options) {
    var config = { // defaults
        list: 'string value',
        of: [a, b, c],
        optional: {x: y},
        objects: function(param){
           // do stuff here
        }
    }; 
    if (options !== undefined){
        for (i in config) {
            if (config.hasOwnProperty(i)){
                if (options[i] !== undefined) { config[i] = options[i]; }
            }
        }
    }
}

Если вы используете jQuery, хороший вариант (особенно для сложных ситуаций) - использовать Метод расширения jQuery.

function foo(options) {

    default_options = {
        timeout : 1000,
        callback : function(){},
        some_number : 50,
        some_text : "hello world"
    };

    options = $.extend({}, default_options, options);
}

Если вы вызовете функцию, то вот так:

foo({timeout : 500});

Тогда переменная параметров будет следующей:

{
    timeout : 500,
    callback : function(){},
    some_number : 50,
    some_text : "hello world"
};

Почему бы не использовать оператор !!? Этот оператор, помещенный перед переменной, превращает ее в логическое значение (если я хорошо понял), поэтому !!undefined и !!null (и даже !!NaN, что может быть довольно интересно) вернут false.

Вот пример:

function foo(bar){
    console.info(!!bar);
}

foo("hey") //=> will log true

foo() //=> will log false

Не работает с логическим значением true, нулем и пустой строкой. Например, foo (0); будет регистрировать ложь, но foo (1) будет регистрировать истину

rosell.dk 18.08.2016 10:15

Иногда вы также можете захотеть проверить тип, особенно если вы используете функцию как геттер и сеттер. Следующий код - ES6 (не работает в EcmaScript 5 или более ранней версии):

class PrivateTest {
    constructor(aNumber) {
        let _aNumber = aNumber;

        //Privileged setter/getter with access to private _number:
        this.aNumber = function(value) {
            if (value !== undefined && (typeof value === typeof _aNumber)) {
                _aNumber = value;
            }
            else {
                return _aNumber;
            }
        }
    }
}

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

this.setCurrent = function(value) {
  this.current = value || 0;
};

Это обязательно означает, что если значение value отсутствует / не передано - установите его на 0.

Довольно круто, да!

Фактически это означает, что «если value эквивалентен false, установите его в 0». Это тонкое, но очень важное различие.

Charles Wood 07.02.2018 18:27

@CharlesWood Значение не передано / присутствует означает только ложь

hhhhh 09.02.2018 16:13

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

Charles Wood 11.02.2018 06:44

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

Charles Wood 11.02.2018 06:45

@CharlesWood извини за опоздание на вечеринку. Я предлагаю вам добавить их в сам ответ с опцией редактирования

hhhhh 17.02.2018 13:36

В ES6 (ES2015) вы можете использовать Параметры по умолчанию

function Test(arg1 = 'Hello', arg2 = 'World!'){
  alert(arg1 + ' ' +arg2);
}

Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!

Этот ответ действительно интересен и может быть полезен оператору. Хотя на самом деле это не ответы вопрос

Ulysse BN 24.07.2017 01:21

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

Andriy2 24.07.2017 01:26

Я хочу сказать, что вы не отвечаете на Как лучше всего определить, не отправляется ли аргумент функции JavaScript. Но на вопрос мог нужно ответить, используя аргументы по умолчанию: например, присвоив вашим аргументам имя "default value" и проверив, действительно ли значение равно "default value".

Ulysse BN 24.07.2017 01:54

fnCalledFunction (Param1, Param2, window.YourOptionalParameter)

Если указанная выше функция вызывается из многих мест, и вы уверены, что первые 2 параметра передаются отовсюду, но не уверены в третьем параметре, вы можете использовать window.

window.param3 будет обрабатывать, если он не определен в вызывающем методе.

function example(arg) {
  var argumentID = '0'; //1,2,3,4...whatever
  if (argumentID in arguments === false) {
    console.info(`the argument with id ${argumentID} was not passed to the function`);
  }
}

Поскольку массивы наследуются от Object.prototype. Считайте ⇑, чтобы сделать мир лучше.

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