Como encurtar o bloco de caixa do switch convertendo um número em um nome de mês?


110

Existe uma maneira de escrever isso em menos linhas, mas ainda facilmente legível?

var month = '';

switch(mm) {
    case '1':
        month = 'January';
        break;
    case '2':
        month = 'February';
        break;
    case '3':
        month = 'March';
        break;
    case '4':
        month = 'April';
        break;
    case '5':
        month = 'May';
        break;
    case '6':
        month = 'June';
        break;
    case '7':
        month = 'July';
        break;
    case '8':
        month = 'August';
        break;
    case '9':
        month = 'September';
        break;
    case '10':
        month = 'October';
        break;
    case '11':
        month = 'November';
        break;
    case '12':
        month = 'December';
        break;
}

7
A resposta de IMHO vidriduch é a mais apropriada. Provavelmente, essa não é a única parte do seu código que requer manipulações de Data (embora a que você mostrou seja particularmente fácil de codificar). Você deve considerar seriamente o uso de bibliotecas Date testadas e existentes.
— coredump

2
Não sei javascript, mas não tem um hashmap, como o dicionário do Python ou o std :: map do C ++?
— Homem Mascarado

28

2
Tantas respostas mudando o comportamento do código ao não levar em conta o padrão '', o que resulta em uma saída indefinida, que é diferente do que o original faz.
— Pieter B

2
Esta não é uma pergunta duplicada> :( esta é uma pergunta completamente diferente, mas a resposta pode ser a mesma.
— Leon Gaban

Respostas:


199

Defina uma matriz e obtenha pelo índice.

var months = ['January', 'February', ...];

var month = months[mm - 1] || '';

23
em vez de mm - 1você também pode definir undefinedcomo o primeiro valor (índice 0) para que os índices da matriz correspondam aos números dos meses
— Touffy

9
var month = month[(mm -1) % 12]
— mpez0

77
@ mpez0 Acho que prefiro saber que alguém conseguiu chegar ao mês número 15, em vez de ocultar o que provavelmente são dados
— inválidos

21
@Touffy, acho que continuaria com mm-1isso months.length==12.
— Teepeemm

48
@Touffy, eu diria que não é uma questão de gosto, mas sim de evitar códigos inteligentes . Imagine-se lendo o de outra pessoa [undefined, 'January', 'February', ...]- acho que sua primeira reação é WTF ?! , o que geralmente não é um bom sinal ...
— miraculixx

81

que tal não usar array :)

var objDate = new Date("10/11/2009"),
    locale = "en-us",
    month = objDate.toLocaleString(locale, { month: "long" });

console.log(month);

// or if you want the shorter date: (also possible to use "narrow" for "O"
console.log(objDate.toLocaleString(locale, { month: "short" }));

de acordo com esta resposta Obtenha o nome do mês de Data de David Storey


2
Dada a definição do problema em questão, sua resposta não é realmente resolver esse problema, mas uma solução diferente que pode ser correta em um contexto diferente. A resposta selecionada ainda é a melhor e mais eficiente.
— TechMaze

6
Apenas o new Date("2009-11-10")formato tem garantia de análise (consulte esta especificação: ecma-international.org/publications/standards/Ecma-262.htm ). Outros formatos de data (incluindo um em sua resposta) podem ser analisados ​​se o navegador assim escolher e, portanto, não são portáteis.
— jb.

58

Experimente isto:

var months = {'1': 'January', '2': 'February'}; //etc
var month = months[mm];

Observe que mmpode ser um número inteiro ou uma string e ainda funcionará.

Se você quiser que chaves inexistentes resultem em uma string vazia ''(em vez de undefined), adicione esta linha:

month = (month == undefined) ? '' : month;

JSFiddle .


4
Em conjuntos de dados maiores do que "meses do ano", isso provavelmente será mais eficiente.
— DGM

3
Este é efetivamente um enum (ou seja, torná-lo imutável), defina-o como var months = Object.freeze({'1': 'January', '2': 'February'}); //etcSee Enums in JavaScript?
— Alexander

1
@Alexander Se você trocar a chave e os valores, sim, é semelhante a um enum.
— Mas eu não sou um Wrapper Class

26

Você pode criar uma matriz e procurar o nome do mês:

var months = ['January','February','March','April','May','June','July','August','September','October','November','December']


var month = months[mm-1] || '';

Veja a resposta de @CupawnTae para o raciocínio por trás do código || ''


ao invés de começar com 0 índice de você poderia manter undefinedem 0 como var months = [ undefined, 'January','February','March', .....Desta forma, você vai usarmonth = months[mm];
— Grijesh Chauhan

@GrijeshChauhan: evite códigos 'inteligentes'. A primeira reação da próxima pessoa seria wtf. É apenas um '-1', meses. O comprimento será então 13, wtf ^ 2. programmers.stackexchange.com/questions/91854/…
— RvdK

19

Seja cuidadoso!

O que deve disparar imediatamente o alarme é a primeira linha: var month = '';- por que essa variável está sendo inicializada com uma string vazia, em vez de nullou undefined? Pode ter sido apenas um hábito ou código copiado / colado, mas a menos que você saiba com certeza, não é seguro ignorá-lo quando estiver refatorando o código.

Se você usar uma matriz de nomes de meses e alterar seu código para, var month = months[mm-1];você está mudando o comportamento, porque agora para números fora do intervalo, ou valores não numéricos, monthestarão undefined. Você pode saber que isso é ok, mas existem muitas situações em que isso seria ruim.

Por exemplo, digamos que você switchesteja em uma função monthToName(mm)e alguém a esteja chamando assim:

var monthName = monthToName(mm);

if (monthName === '') {
  alert("Please enter a valid month.");
} else {
  submitMonth(monthName);
}

Agora, se você mudar para usar uma matriz e retornar monthName[mm-1], o código de chamada não funcionará mais como pretendido e enviará undefinedvalores quando for para exibir um aviso. Não estou dizendo que este é um bom código, mas a menos que você saiba exatamente como o código está sendo usado, você não pode fazer suposições.

Ou talvez a inicialização original estivesse lá porque algum código mais abaixo na linha assume que monthsempre será uma string e faz algo como month.length- isso resultará em uma exceção sendo lançada para meses inválidos e potencialmente matar o script de chamada completamente.

Se você fazer conhecer todo o contexto - por exemplo, é tudo seu próprio código, e mais ninguém nunca vai usá-lo, e você confiar em si mesmo não se esqueça que você fez a algum mudança no futuro - pode ser seguro para alterar o comportamento assim, mas muitos bugs vêm desse tipo de suposição de que na vida real é muito melhor programar defensivamente e / ou documentar o comportamento por completo.

A resposta de Wasmoo acertou (EDITAR: várias outras respostas, incluindo a aceita, também foram corrigidas) - você pode usar months[mm-1] || ''ou, se preferir, deixar mais óbvio o que está acontecendo, algo como:

var months = ['January', 'February', ...];

var month;

if (mm >= 1 && m <= 12) {
  month = months[mm - 1];
} else {
  month = ''; // empty string when not a valid month
}

1
Ninguém mais mencionou a mudança de comportamento ainda, então isso deve ser levado em consideração ao refatorar o código.
— Mauro

Esta resposta está certa. A maioria das outras respostas altera o comportamento do código de maneira sutil. Isso pode não importar ou pode se tornar irritantemente difícil de encontrar bug.
— Pieter B

Ah, então é sempre melhor iniciar uma var para undefined? Isso economiza desempenho se o tipo for convertido?
— Leon Gaban

2
@LeonGaban não é sobre desempenho: a pergunta original inicializou a variável com uma string vazia e deixou como se nenhum mês válido fosse selecionado, enquanto muitas das outras respostas aqui ignoraram esse fato e mudaram o comportamento retornando undefinedquando a entrada não foi 't 1..12. Exceto em circunstâncias muito excepcionais, o comportamento correto sempre supera o desempenho.
— CupawnTae

17

Para completar, gostaria de complementar as respostas atuais. Basicamente, você pode omitir a breakpalavra - chave e retornar diretamente um valor apropriado. Essa tática é útil se o valor não puder ser armazenado em uma tabela de consulta pré-computada.

function foo(mm) {
    switch(mm) {
        case '1':  return 'January';
        case '2':  return 'February';
        case '3':  return 'March';
        case '4':  return 'April';
        // [...]
        case '12': return 'December';
    }
    return '';
}

Mais uma vez, usar uma tabela de consulta ou funções de data é mais sucinto e subjetivamente melhor .


16

Você pode fazer isso usando uma matriz:

var months = ['January', 'February', 'March', 'April', 
              'May', 'June', 'July', 'August', 
              'September', 'October', 'November', 'December'];

var month = months[mm - 1] || '';

12

Aqui está outra opção que usa apenas 1 variável e ainda aplica o valor padrão ''quando mmestá fora do intervalo.

var month = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ][mm-1] || '';

A verificação de alcance e o lançamento de uma exceção também podem funcionar. E retornar "Erro" ou "Indefinido" pode ser uma alternativa para a string vazia.
— ChuckCottrill

9

Você pode escrevê-lo como uma expressão em vez de um switch, usando operadores condicionais:

var month =
  mm == 1 ? 'January' :
  mm == 2 ? 'February' :
  mm == 3 ? 'March' :
  mm == 4 ? 'April' :
  mm == 5 ? 'May' :
  mm == 6 ? 'June' :
  mm == 7 ? 'July' :
  mm == 8 ? 'August' :
  mm == 9 ? 'September' :
  mm == 10 ? 'October' :
  mm == 11 ? 'November' :
  mm == 12 ? 'December' :
  '';

Se você não viu operadores condicionais encadeados antes, pode parecer mais difícil de ler no início. Escrevê-lo como uma expressão torna um aspecto ainda mais fácil de ver do que o código original; é claro que a intenção do código é atribuir um valor à variável month.


1
Eu pretendia sugerir este também. Na verdade, é muito legível, embora conciso, e funcionaria bem para mapeamentos esparsos e chaves não numéricas, o que a solução de array não funciona. PS Eu também recebi um downvote inexplicável aleatório na minha resposta - provavelmente o mesmo artista drive-by.
— CupawnTae

6

Com base na resposta de Cupawn Tae anterior, eu encurtaria para:

var months = ['January', 'February', ...];
var month = (mm >= 1 && mm <= 12) ? months[mm - 1] : '';

Como alternativa, sim, agradeço, menos legível:

var month = months[mm - 1] || ''; // as mentioned further up

Você pode pular (!!months[mm - 1])e simplesmente fazer months[mm - 1].
— YingYang

Isso resultaria em indefinido se o índice da matriz estivesse fora do intervalo!
— NeilElliott-NSDev

months[mm - 1]retornará undefinedpara um índice que está fora do intervalo. Como undefinedé falso, você acabará com ''o valor de month.
— YingYang

Conforme declarado em outras respostas, você pode simplificar esta linha ainda mais:var month = months[mm - 1] || '';
— YingYang

Embora eu tenha notado mais acima (não estava por perto quando postei), var mês = meses [mm - 1] || ''; O que seria ainda mais limpo.
— NeilElliott-NSDev

4
var getMonth=function(month){
   //Return string to number.
    var strMonth = ['January', 'February', 'March',
             'April', 'May', 'June', 'July',
             'August', 'September', 'October',
             'November', 'December'
            ];
    //return number to string.
    var intMonth={'January':1, 'February':2, 'March':3,
             'April':4, 'May':5, 'June':6, 'July':7,
             'August':8, 'September':9, 'October':10,
             'November':11, 'December':12
            };
    //Check type and return 
    return (typeof month === "number")?strMonth[month-1]:intMonth[month]
}

4

Como @vidriduch, gostaria de sublinhar a importância de i20y ("internacionalização") do código no contexto atual e sugerir a seguinte solução concisa e robusta em conjunto com o teste unitário.

function num2month(month, locale) {
    if (month != Math.floor(month) || month < 1 || month > 12)
        return undefined;
    var objDate = new Date(Math.floor(month) + "/1/1970");
    return objDate.toLocaleString(locale, {month: "long"});
}

/* Test/demo */
for (mm = 1; mm <= 12; mm++)
    document.writeln(num2month(mm, "en") + " " +
                     num2month(mm, "ar-lb") + "<br/>");
document.writeln(num2month("x", "en") + "<br/>");
document.writeln(num2month(.1, "en") + "<br/>");
document.writeln(num2month(12.5, "en" + "<br/>"));

Tento ficar o mais próximo possível da questão original, ou seja, transformar os números de 1 a 12 em nomes de meses, não apenas para um caso especial, mas retornar undefinedem caso de argumentos inválidos, usando algumas das críticas anteriormente adicionadas e conteúdos de outras respostas. (A mudança de undefinedpara ''é trivial, caso a correspondência exata seja necessária.)


0

Eu escolheria a solução do wasmoo , mas ajustaria assim:

var month = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
][mm-1] || '';

É exatamente o mesmo código, na verdade, mas recuado de forma diferente, o que o IMO o torna mais legível.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.