Як скоротити блок корпусу комутатора, перетворюючи число на ім'я місяця?


110

Чи є спосіб написати це меншою кількістю рядків, але все ще легко читається?

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
Відповідь ІМХО відрідуха є найбільш прийнятною. Це, мабуть, не єдина частина вашого коду, яка вимагає маніпуляцій з датою (навіть незважаючи на те, що той, який ви показали, дуже легко кодувати). Слід серйозно розглянути можливість використання існуючих, перевірених бібліотек дат.
coredump

2
Я не знаю JavaScript, але чи не має він хешмапу, як словник Python або C ++ 'std :: map?
Людина в масках

28
Чи не припустимо це для codereview.stackexchange.com ?
Локо

2
Так багато відповідей, що змінюють поведінку коду, не враховуючи типовий параметр '', що призводить до невизначеного виводу, який відрізняється від того, що робить оригінал.
Пітер Б

2
Це не повторне запитання> :( це задає зовсім інше запитання, проте відповідь може бути однаковою.
Леон Габан

Відповіді:


199

Визначте масив, а потім отримайте за індексом.

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

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

23
замість mm - 1вас також можна встановити undefinedяк перше значення (індекс 0), тому показники масиву будуть відповідати числам місяця
Touffy

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

77
@ mpez0 Я думаю, що я вважаю за краще знати, що комусь вдалося придумати номер 15 місяця, а не приховувати, що, мабуть, погані дані
Ізката

21
@Touffy, я думаю, я би дотримувався цього mm-1, так що months.length==12.
Teepeemm

48
@Touffy я б заперечив, що це не питання смаку, а питання уникання розумного коду . Уявіть, що ви читаєте ще якісь речі [undefined, 'January', 'February', ...]- я найкраще, щоб ваша перша реакція була WTF ?! , що зазвичай не є гарним знаком ...
miraculixx

81

а як взагалі не використовувати масив :)

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

відповідно до цієї відповіді. Отримайте ім’я місяця від Date від David Storey


2
З огляду на проблему, про яку йдеться, ваша відповідь насправді не вирішує цю проблему, а якесь інше рішення, яке може бути правильним в іншому контексті. Вибрана відповідь як і раніше є найкращою та найбільш ефективною.
TechMaze

6
Тільки new Date("2009-11-10")формат гарантовано буде оброблений (див це Specifiation: ecma-international.org/publications/standards/Ecma-262.htm ). Інші формати дати (включаючи один у вашій відповіді) можуть бути проаналізовані, якщо браузер обрав це, а значить, не є портативним.
jb.

58

Спробуйте це:

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

Зверніть увагу, що це mmможе бути ціле число або рядок, і воно все одно буде працювати.

Якщо ви хочете, щоб неіснуючі ключі привели до порожнього рядка ''(замість undefined), додайте цей рядок:

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

JSFiddle .


4
Що стосується більших наборів даних, ніж "місяців року", це, ймовірно, буде більш ефективним.
DGM

3
Це фактично enum (тобто робить його непорушним), визначте його як var months = Object.freeze({'1': 'January', '2': 'February'}); //etcSee Enums in JavaScript?
Олександр

1
@Alexander Якщо ви поміняєте клавішу та значення, то так, це схоже на перерахунок.
Але я не клас Wrapper

26

Ви можете створити масив замість цього і знайти ім'я місяця:

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


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

Дивіться відповідь @CupawnTae щодо раціональності за кодом || ''


а не почати з індексом 0 можна зберегти undefinedв 0 якості var months = [ undefined, 'January','February','March', .....Таким чином , ви будете використовуватиmonth = months[mm];
Grijesh CHAUHAN

@GrijeshChauhan: будь ласка, уникайте "розумного" коду. Перша реакція наступної людини повинна бути wtf. Це лише '-1', місяці. Тоді тривалість буде 13, wtf ^ 2. programmers.stackexchange.com/questions/91854/…
RvdK

19

Будь обережний!

Перший рядок повинен негайно викликати дзвінки тривоги: var month = '';- чому ця змінна ініціалізується у порожній рядок, а не nullчи undefined? Це може бути просто звичка або копіювати / вставляти код, але якщо ви точно не знаєте, ігнорувати його, коли ви рефакторинг код, не безпечно.

Якщо ви використовуєте масив назв місяців і змінюєте свій код, var month = months[mm-1];ви змінюєте поведінку, тому що тепер для чисел, що знаходяться за межами діапазону, або нечислових значень, monthце буде undefined. Ви можете знати, що це нормально, але є багато ситуацій, коли це було б погано.

Наприклад, скажімо, що ваша switchфункція monthToName(mm), і хтось називає вашу функцію так:

var monthName = monthToName(mm);

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

Тепер, якщо ви перейдете на використання масиву та повернення monthName[mm-1], код виклику більше не буде функціонувати за призначенням, і він подаватиме undefinedзначення, коли передбачається відображати попередження. Я не кажу, що це хороший код, але якщо ви точно не знаєте, як використовується код, ви не можете робити припущення.

А може, оригінальна ініціалізація була там, тому що деякий код у нижній частині рядка передбачає, що monthце завжди буде рядок, і робить щось на кшталт month.length- це призведе до того, що виняток буде кинутий за недійсні місяці і потенційно повністю знищить викликовий скрипт.

Якщо ви робите знати весь контекст - наприклад , все це ваш власний код, і ніхто ще ніколи не збирається використовувати його, і ви довіряєте собі , не забувайте , що ви зробили зміни коли - небудь в майбутньому - це може бути безпечним , щоб змінити поведінку як це, але так багато помилок походять з такого припущення, що в реальному житті ти набагато краще програмуєш оборонно та / або ретельно документуєш поведінку.

Відповідь Wasmoo відповідає правильності (EDIT: низка інших відповідей, включаючи прийняту, тепер уже виправлена) - ви можете скористатися months[mm-1] || ''або, якщо ви хочете, щоб це стало очевидніше з першого погляду, що відбувається, щось на кшталт:

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
Ніхто ще не згадував про зміну поведінки, тому це слід враховувати при повторному факторингу коду.
Мауро

Ця відповідь на місці. Більшість інших відповідей тонко змінюють поведінку коду. Це може не мати значення, або це може стати настільки важко важким знайти помилку.
Пітер Б

Так, це завжди краще, щоб почати вар undefined? Чи зберігає це ефективність, якщо тип перетворюється?
Леон Габан

2
@LeonGaban справа не в продуктивності: оригінальне запитання ініціалізувало змінну в порожній рядок і залишило її при цьому, якщо не було обрано дійсного місяця, тоді як багато інших відповідей тут ігнорували цей факт і змінили поведінку, повернувшись, undefinedколи вхід не був 'т 1..12. За винятком дуже виняткових обставин, правильна поведінка щоразу перемагає працездатність.
CupawnTae

17

Для повноти я хотів би доповнити поточні відповіді. В основному, ви можете опустити breakключове слово і безпосередньо повернути відповідне значення. Ця тактика корисна, якщо значення не можна зберегти у попередньо обчисленій таблиці пошуку.

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

Ще раз, використання довідкової таблиці або функцій дати є більш стислим та суб'єктивно кращим .


16

Ви можете зробити це за допомогою масиву:

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

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

12

Ось ще один варіант, який використовує лише 1 змінну і все ще застосовує значення за замовчуванням, ''коли mmзнаходиться поза діапазоном.

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

Перевірка дальності та викид виключення також можуть працювати. І повернення "Помилка" або "Невизначено" може бути альтернативою порожній рядку.
ChuckCottrill

9

Ви можете записати це як вираз замість комутатора, використовуючи умовні оператори:

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' :
  '';

Якщо ви ще не бачили прикованих умовних операторів до цього, спочатку це може здатися важче прочитати. Запис його як вираз робить один аспект ще простішим для прогляду, ніж оригінальний код; зрозуміло, що метою коду є присвоєння значення змінній month.


1
Я мав намір запропонувати і це. Це насправді дуже легко читати, залишаючись лаконічним, і добре працюватиме для розріджених відображень та нечислових ключів, що рішення масиву не відповідає. PS Я отримав випадковий незрозумілий відгук і на свою відповідь - ймовірно, той самий художник-драйвер.
CupawnTae

6

Спираючись на попередній відповідь Купаун Та, я скоротив його до:

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

Як варіант, так, я вдячний, менш читабельний:

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

Можна пропустити (!!months[mm - 1])і просто зробити months[mm - 1].
YingYang

Це призведе до невизначеності, якщо індекс масиву виявиться поза діапазоном!
NeilElliott-NSDev

months[mm - 1]повернеться undefinedза індекс, який знаходиться поза діапазоном. Оскільки undefinedце хибність, ви закінчитеся ''як значення month.
YingYang

Як зазначено в інших відповідях, ви можете ще більше спростити цей рядок:var month = months[mm - 1] || '';
YingYang

Хоча я помітив далі (не було, коли я публікував), var місяць = місяці [мм - 1] || ''; Що було б ще акуратніше.
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

Як і @vidriduch, я хотів би підкреслити важливість коду i20y («інтернаціоналізація») у сучасному контексті та запропонувати наступне стисле та надійне рішення разом із унітарним тестом.

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/>"));

Я намагаюся максимально наблизитись до оригінального питання, тобто перетворять числа від 1 до 12 в назви місяців не лише для одного окремого випадку, але повертаюсь undefinedу разі невірних аргументів, використовуючи деякі раніше додані критики до вмісту інших відповіді. (Перехід від на undefinedдо ''дрібниць, якщо потрібна точна відповідність.)


0

Я б пішов на рішення wasmoo , але налаштуйте його так:

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

Це саме той самий код, насправді, але з різним відступом, який IMO робить його більш читабельним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.