Как лучше всего определить, не отправляется ли аргумент в функцию 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);
}

12 ответов


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

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

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

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

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

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

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

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

еще один хороший способ, чтобы задать значения по умолчанию, используя arguments.length возможно путем падать через ярлыки оператора переключателя:

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
}

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


Если вы используете 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});

переменная options будет тогда:

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

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

if(! argument2) {  

}

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

(с одновременным ограничением, что я бы не разрешил законное значение null для argument2 что имеет какое-то другое значение; но это было бы действительно путаешь.)

EDIT:

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

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

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

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

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

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

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


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

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;

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


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

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]; }
            }
        }
    }
}

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

вот пример:

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

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

foo() //=> will log false

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

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

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

несколько раз вы также можете проверить тип, особенно если вы используете функцию в качестве геттера и сеттера. Следующий код-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.

прикольно, да!


fnCalledFunction (Param1, Param2, window.YourOptionalParameter)

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