Qual a melhor forma de determinar se um argumento não é enviado para a função JavaScript

StackOverflow https://stackoverflow.com/questions/411352

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu vi agora 2 métodos para determinar se um argumento foi passado para uma função JavaScript. Eu estou querendo saber se um método é melhor que o outro, ou se é apenas ruim para usar?

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

      alert(argument2);
 }

 Test('test');

ou

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

      alert(argument2);
 }

 Test('test');

Tanto quanto eu posso dizer, ambos resultado da mesma coisa, mas eu tenho usado apenas o primeiro antes em produção.

Outra opção como mencionado por Tom :

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

    alert(argument2);
}

De acordo com o comentário de Juan, que seria melhor para mudar a sugestão de Tom para:

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

    alert(argument2);
}
Foi útil?

Solução

Existem várias maneiras diferentes para verificar se um argumento foi passado para uma função. Além dos dois que você mencionou na sua pergunta (original) - verificando arguments.length ou usando o operador || para fornecer valores padrão -. Também se pode verificar explicitamente os argumentos para undefined via argument2 === undefined ou typeof argument2 === 'undefined' se um é paranóico (ver comentários)

Usando o operador || tornou-se prática padrão - todos os miúdos legal fazê-lo - mas tenha cuidado: o valor padrão será acionado se os avalia argumento para false, o que significa que poderia realmente ser undefined, null, false, 0, '' (ou qualquer outra coisa para a qual Boolean(...) retornos false).

Então a questão é quando usar cada cheque, como todos eles de rendimento resultados ligeiramente diferentes.

Verificar arguments.length exibe o comportamento 'mais correta', mas pode não ser viável se houver mais de um argumento opcional.

O teste para undefined está próximo 'melhor' -. Ele só 'não' se a função é explicitamente chamado com um valor undefined, que com toda a probabilidade deve ser tratado da mesma forma que omitindo o argumento

O uso do operador || uso pode desencadear do valor padrão, mesmo se um argumento válido é fornecido. Por outro lado, o seu comportamento pode realmente ser desejado.

Para resumir: usá-lo somente se você souber o que está fazendo

Na minha opinião, usando || também é o caminho a percorrer se há mais de um argumento opcional e um não quer passar um literal objeto como uma solução alternativa para parâmetros nomeados.

Outra boa maneira de fornecer valores padrão usando arguments.length é possível por caindo através das etiquetas de uma instrução 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
}

Isto tem a desvantagem que a intenção do programador não é (visualmente) óbvio e utilizações 'números mágicos'; é, portanto, possivelmente, propenso a erros.

Outras dicas

Se você estiver usando jQuery, uma opção que é bom (especialmente para situações complicadas) é usar jQuery estender método .

function foo(options) {

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

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

Se você chamar a função, em seguida, como este:

foo({timeout : 500});

A variável opções, então, seria:

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

Este é um dos poucos casos em que eu encontrar o teste:

if(! argument2) {  

}

funciona muito bem e carrega a implicação correta sintaticamente.

(Com a restrição simultânea que eu não permitiria que um valor nulo legítima para argument2 que tem algum outro significado; mas isso seria realmente confundindo.)

EDIT:

Este é realmente um bom exemplo de uma diferença estilística entre linguagens fracamente tipadas e fortemente tipado; e uma opção estilística que ofereça javascript em espadas.

A minha preferência pessoal (sem críticas significou para outras preferências) é minimalismo. Quanto menos o código tem a dizer, enquanto eu sou consistente e concisa, a menos que outra pessoa tem de compreender a corretamente inferir o meu significado.

Uma implicação de que a preferência é que eu não quero - não achar útil - pile-se um monte de testes tipo de dependência. Em vez disso, eu tento fazer o código significa o que parece que isso significa; e único teste para o que eu realmente precisa para testar.

Um dos agravos I encontrar no código de alguns outros povos é a necessidade de descobrir se ou não eles esperam que, no contexto maior, para realmente correr para os casos eles estão testando para. Ou se eles estão tentando teste para todo o possível, na esperança de que eles não antecipar o contexto completamente suficiente. O que significa que acabam necessitando de rastreá-los exaustivamente em ambas as direções antes que eu possa confiantemente refactor ou modificar qualquer coisa. I figura que há uma boa chance de que eles poderiam ter colocar os vários testes no lugar, porque eles previram circunstâncias em que seriam necessários (e que normalmente não são aparentes para mim).

(considero que uma desvantagem séria na forma como esses pessoas usam linguagens dinâmicas. Muitas vezes as pessoas não querem desistir de todas as provas estáticas e acabam fingindo.)

Eu vi isso mais flagrantemente na comparação abrangente código ActionScript 3 com código javascript elegante. A AS3 pode ser 3 ou 4 vezes o volume dos js, e a confiabilidade Suspeito é, pelo menos, não é melhor, apenas por causa do número (3-4X) de codificação de decisões que foram tomadas.

Como você diz, Shog9, YMMV. : D

Existem diferenças significativas. Vamos configurar alguns casos de teste:

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

Com o primeiro método que você descreve, apenas o segundo teste usará o valor padrão. O segundo método será o padrão todos, mas o primeiro (como JS irá converter undefined, null, 0 e "" no false boolean. E se você fosse usar o método de Tom, apenas o quarto teste usará o padrão!

Qual o método que você escolher realmente depende do seu comportamento pretendido. Se outras que undefined valores são admissíveis para argument2, então você provavelmente vai querer alguma variação no primeiro; Se um valor diferente de zero, não nula, não-vazia é desejado, em seguida, o segundo método é ideal -. de facto, é muitas vezes usado para eliminar rapidamente uma ampla gama de valores como de consideração

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

Em ES6 (ES2015) você pode usar Padrão parâmetros

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

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

Eu sinto muito, eu comentário ainda ainda cant, de modo a responder a resposta de Tom ... Em javascript (indefinido! = Null) == false Na verdade essa função não vai funcionar com "null", você deve usar "indefinido"

Pode ser conveniente para a detecção argumento abordagem ao evocar a sua função com um objeto de propriedades opcionais:

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

Por que não usar o operador !!? Este operador, colocado antes da variável, transformá-lo para um booleano (se eu entendi bem), então !!undefined e !!null (e mesmo !!NaN, que pode ser bastante interessante) irá retornar false.

Aqui está um exemple:

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

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

foo() //=> will log false

Algumas vezes você também pode querer verificar para o tipo, especialmente se você estiver usando a função de getter e setter. O código a seguir é ES6 (não será executado em EcmaScript 5 anos ou mais):

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

Há um caminho complicado também para encontrar, se um parâmetro é passado para uma função ou não . Ter um olhar para o exemplo abaixo:

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

Este meios necessários que se o valor de value não está presente / passado -. Set para 0

Muito legal hein!

fnCalledFunction (Param1, Param2, window.YourOptionalParameter)

Se a função acima é chamado de muitos lugares e você tem certeza primeira 2 parâmetros são passados ??de todos os lugares, mas não tem certeza sobre terceiro parâmetro, então você pode usar a janela.

window.param3 irá lidar com se não for definida a partir do método chamador.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top